CyaSSL is an SSL library for devices like mbed.

Dependents:   cyassl-client Sync

Committer:
toddouska
Date:
Sat Feb 05 01:09:17 2011 +0000
Revision:
0:5045d2638c29
Beta Version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
toddouska 0:5045d2638c29 1 /* integer.c
toddouska 0:5045d2638c29 2 *
toddouska 0:5045d2638c29 3 * Copyright (C) 2006-2009 Sawtooth Consulting Ltd.
toddouska 0:5045d2638c29 4 *
toddouska 0:5045d2638c29 5 * This file is part of CyaSSL.
toddouska 0:5045d2638c29 6 *
toddouska 0:5045d2638c29 7 * CyaSSL is free software; you can redistribute it and/or modify
toddouska 0:5045d2638c29 8 * it under the terms of the GNU General Public License as published by
toddouska 0:5045d2638c29 9 * the Free Software Foundation; either version 2 of the License, or
toddouska 0:5045d2638c29 10 * (at your option) any later version.
toddouska 0:5045d2638c29 11 *
toddouska 0:5045d2638c29 12 * CyaSSL is distributed in the hope that it will be useful,
toddouska 0:5045d2638c29 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
toddouska 0:5045d2638c29 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
toddouska 0:5045d2638c29 15 * GNU General Public License for more details.
toddouska 0:5045d2638c29 16 *
toddouska 0:5045d2638c29 17 * You should have received a copy of the GNU General Public License
toddouska 0:5045d2638c29 18 * along with this program; if not, write to the Free Software
toddouska 0:5045d2638c29 19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
toddouska 0:5045d2638c29 20 */
toddouska 0:5045d2638c29 21
toddouska 0:5045d2638c29 22 /*
toddouska 0:5045d2638c29 23 * Based on public domain LibTomMath 0.38 by Tom St Denis, tomstdenis@iahu.ca,
toddouska 0:5045d2638c29 24 * http://math.libtomcrypt.com
toddouska 0:5045d2638c29 25 */
toddouska 0:5045d2638c29 26
toddouska 0:5045d2638c29 27
toddouska 0:5045d2638c29 28 #ifndef USE_FAST_MATH
toddouska 0:5045d2638c29 29
toddouska 0:5045d2638c29 30 #include "integer.h"
toddouska 0:5045d2638c29 31
toddouska 0:5045d2638c29 32
toddouska 0:5045d2638c29 33 /* handle up to 6 inits */
toddouska 0:5045d2638c29 34 int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e,
toddouska 0:5045d2638c29 35 mp_int* f)
toddouska 0:5045d2638c29 36 {
toddouska 0:5045d2638c29 37 int res = MP_OKAY;
toddouska 0:5045d2638c29 38
toddouska 0:5045d2638c29 39 if (a && ((res = mp_init(a)) != MP_OKAY))
toddouska 0:5045d2638c29 40 return res;
toddouska 0:5045d2638c29 41
toddouska 0:5045d2638c29 42 if (b && ((res = mp_init(b)) != MP_OKAY)) {
toddouska 0:5045d2638c29 43 mp_clear(a);
toddouska 0:5045d2638c29 44 return res;
toddouska 0:5045d2638c29 45 }
toddouska 0:5045d2638c29 46
toddouska 0:5045d2638c29 47 if (c && ((res = mp_init(c)) != MP_OKAY)) {
toddouska 0:5045d2638c29 48 mp_clear(a); mp_clear(b);
toddouska 0:5045d2638c29 49 return res;
toddouska 0:5045d2638c29 50 }
toddouska 0:5045d2638c29 51
toddouska 0:5045d2638c29 52 if (d && ((res = mp_init(d)) != MP_OKAY)) {
toddouska 0:5045d2638c29 53 mp_clear(a); mp_clear(b); mp_clear(c);
toddouska 0:5045d2638c29 54 return res;
toddouska 0:5045d2638c29 55 }
toddouska 0:5045d2638c29 56
toddouska 0:5045d2638c29 57 if (e && ((res = mp_init(e)) != MP_OKAY)) {
toddouska 0:5045d2638c29 58 mp_clear(a); mp_clear(b); mp_clear(c); mp_clear(d);
toddouska 0:5045d2638c29 59 return res;
toddouska 0:5045d2638c29 60 }
toddouska 0:5045d2638c29 61
toddouska 0:5045d2638c29 62 if (f && ((res = mp_init(f)) != MP_OKAY)) {
toddouska 0:5045d2638c29 63 mp_clear(a); mp_clear(b); mp_clear(c); mp_clear(d); mp_clear(e);
toddouska 0:5045d2638c29 64 return res;
toddouska 0:5045d2638c29 65 }
toddouska 0:5045d2638c29 66
toddouska 0:5045d2638c29 67 return res;
toddouska 0:5045d2638c29 68 }
toddouska 0:5045d2638c29 69
toddouska 0:5045d2638c29 70
toddouska 0:5045d2638c29 71 /* init a new mp_int */
toddouska 0:5045d2638c29 72 int mp_init (mp_int * a)
toddouska 0:5045d2638c29 73 {
toddouska 0:5045d2638c29 74 int i;
toddouska 0:5045d2638c29 75
toddouska 0:5045d2638c29 76 /* allocate memory required and clear it */
toddouska 0:5045d2638c29 77 a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC, 0,
toddouska 0:5045d2638c29 78 DYNAMIC_TYPE_BIGINT);
toddouska 0:5045d2638c29 79 if (a->dp == NULL) {
toddouska 0:5045d2638c29 80 return MP_MEM;
toddouska 0:5045d2638c29 81 }
toddouska 0:5045d2638c29 82
toddouska 0:5045d2638c29 83 /* set the digits to zero */
toddouska 0:5045d2638c29 84 for (i = 0; i < MP_PREC; i++) {
toddouska 0:5045d2638c29 85 a->dp[i] = 0;
toddouska 0:5045d2638c29 86 }
toddouska 0:5045d2638c29 87
toddouska 0:5045d2638c29 88 /* set the used to zero, allocated digits to the default precision
toddouska 0:5045d2638c29 89 * and sign to positive */
toddouska 0:5045d2638c29 90 a->used = 0;
toddouska 0:5045d2638c29 91 a->alloc = MP_PREC;
toddouska 0:5045d2638c29 92 a->sign = MP_ZPOS;
toddouska 0:5045d2638c29 93
toddouska 0:5045d2638c29 94 return MP_OKAY;
toddouska 0:5045d2638c29 95 }
toddouska 0:5045d2638c29 96
toddouska 0:5045d2638c29 97
toddouska 0:5045d2638c29 98 /* clear one (frees) */
toddouska 0:5045d2638c29 99 void
toddouska 0:5045d2638c29 100 mp_clear (mp_int * a)
toddouska 0:5045d2638c29 101 {
toddouska 0:5045d2638c29 102 int i;
toddouska 0:5045d2638c29 103
toddouska 0:5045d2638c29 104 /* only do anything if a hasn't been freed previously */
toddouska 0:5045d2638c29 105 if (a->dp != NULL) {
toddouska 0:5045d2638c29 106 /* first zero the digits */
toddouska 0:5045d2638c29 107 for (i = 0; i < a->used; i++) {
toddouska 0:5045d2638c29 108 a->dp[i] = 0;
toddouska 0:5045d2638c29 109 }
toddouska 0:5045d2638c29 110
toddouska 0:5045d2638c29 111 /* free ram */
toddouska 0:5045d2638c29 112 XFREE(a->dp, 0, DYNAMIC_TYPE_BIGINT);
toddouska 0:5045d2638c29 113
toddouska 0:5045d2638c29 114 /* reset members to make debugging easier */
toddouska 0:5045d2638c29 115 a->dp = NULL;
toddouska 0:5045d2638c29 116 a->alloc = a->used = 0;
toddouska 0:5045d2638c29 117 a->sign = MP_ZPOS;
toddouska 0:5045d2638c29 118 }
toddouska 0:5045d2638c29 119 }
toddouska 0:5045d2638c29 120
toddouska 0:5045d2638c29 121
toddouska 0:5045d2638c29 122 /* get the size for an unsigned equivalent */
toddouska 0:5045d2638c29 123 int mp_unsigned_bin_size (mp_int * a)
toddouska 0:5045d2638c29 124 {
toddouska 0:5045d2638c29 125 int size = mp_count_bits (a);
toddouska 0:5045d2638c29 126 return (size / 8 + ((size & 7) != 0 ? 1 : 0));
toddouska 0:5045d2638c29 127 }
toddouska 0:5045d2638c29 128
toddouska 0:5045d2638c29 129
toddouska 0:5045d2638c29 130 /* returns the number of bits in an int */
toddouska 0:5045d2638c29 131 int
toddouska 0:5045d2638c29 132 mp_count_bits (mp_int * a)
toddouska 0:5045d2638c29 133 {
toddouska 0:5045d2638c29 134 int r;
toddouska 0:5045d2638c29 135 mp_digit q;
toddouska 0:5045d2638c29 136
toddouska 0:5045d2638c29 137 /* shortcut */
toddouska 0:5045d2638c29 138 if (a->used == 0) {
toddouska 0:5045d2638c29 139 return 0;
toddouska 0:5045d2638c29 140 }
toddouska 0:5045d2638c29 141
toddouska 0:5045d2638c29 142 /* get number of digits and add that */
toddouska 0:5045d2638c29 143 r = (a->used - 1) * DIGIT_BIT;
toddouska 0:5045d2638c29 144
toddouska 0:5045d2638c29 145 /* take the last digit and count the bits in it */
toddouska 0:5045d2638c29 146 q = a->dp[a->used - 1];
toddouska 0:5045d2638c29 147 while (q > ((mp_digit) 0)) {
toddouska 0:5045d2638c29 148 ++r;
toddouska 0:5045d2638c29 149 q >>= ((mp_digit) 1);
toddouska 0:5045d2638c29 150 }
toddouska 0:5045d2638c29 151 return r;
toddouska 0:5045d2638c29 152 }
toddouska 0:5045d2638c29 153
toddouska 0:5045d2638c29 154
toddouska 0:5045d2638c29 155 /* store in unsigned [big endian] format */
toddouska 0:5045d2638c29 156 int mp_to_unsigned_bin (mp_int * a, unsigned char *b)
toddouska 0:5045d2638c29 157 {
toddouska 0:5045d2638c29 158 int x, res;
toddouska 0:5045d2638c29 159 mp_int t;
toddouska 0:5045d2638c29 160
toddouska 0:5045d2638c29 161 if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
toddouska 0:5045d2638c29 162 return res;
toddouska 0:5045d2638c29 163 }
toddouska 0:5045d2638c29 164
toddouska 0:5045d2638c29 165 x = 0;
toddouska 0:5045d2638c29 166 while (mp_iszero (&t) == 0) {
toddouska 0:5045d2638c29 167 #ifndef MP_8BIT
toddouska 0:5045d2638c29 168 b[x++] = (unsigned char) (t.dp[0] & 255);
toddouska 0:5045d2638c29 169 #else
toddouska 0:5045d2638c29 170 b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7));
toddouska 0:5045d2638c29 171 #endif
toddouska 0:5045d2638c29 172 if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) {
toddouska 0:5045d2638c29 173 mp_clear (&t);
toddouska 0:5045d2638c29 174 return res;
toddouska 0:5045d2638c29 175 }
toddouska 0:5045d2638c29 176 }
toddouska 0:5045d2638c29 177 bn_reverse (b, x);
toddouska 0:5045d2638c29 178 mp_clear (&t);
toddouska 0:5045d2638c29 179 return MP_OKAY;
toddouska 0:5045d2638c29 180 }
toddouska 0:5045d2638c29 181
toddouska 0:5045d2638c29 182
toddouska 0:5045d2638c29 183 /* creates "a" then copies b into it */
toddouska 0:5045d2638c29 184 int mp_init_copy (mp_int * a, mp_int * b)
toddouska 0:5045d2638c29 185 {
toddouska 0:5045d2638c29 186 int res;
toddouska 0:5045d2638c29 187
toddouska 0:5045d2638c29 188 if ((res = mp_init (a)) != MP_OKAY) {
toddouska 0:5045d2638c29 189 return res;
toddouska 0:5045d2638c29 190 }
toddouska 0:5045d2638c29 191 return mp_copy (b, a);
toddouska 0:5045d2638c29 192 }
toddouska 0:5045d2638c29 193
toddouska 0:5045d2638c29 194
toddouska 0:5045d2638c29 195 /* copy, b = a */
toddouska 0:5045d2638c29 196 int
toddouska 0:5045d2638c29 197 mp_copy (mp_int * a, mp_int * b)
toddouska 0:5045d2638c29 198 {
toddouska 0:5045d2638c29 199 int res, n;
toddouska 0:5045d2638c29 200
toddouska 0:5045d2638c29 201 /* if dst == src do nothing */
toddouska 0:5045d2638c29 202 if (a == b) {
toddouska 0:5045d2638c29 203 return MP_OKAY;
toddouska 0:5045d2638c29 204 }
toddouska 0:5045d2638c29 205
toddouska 0:5045d2638c29 206 /* grow dest */
toddouska 0:5045d2638c29 207 if (b->alloc < a->used) {
toddouska 0:5045d2638c29 208 if ((res = mp_grow (b, a->used)) != MP_OKAY) {
toddouska 0:5045d2638c29 209 return res;
toddouska 0:5045d2638c29 210 }
toddouska 0:5045d2638c29 211 }
toddouska 0:5045d2638c29 212
toddouska 0:5045d2638c29 213 /* zero b and copy the parameters over */
toddouska 0:5045d2638c29 214 {
toddouska 0:5045d2638c29 215 register mp_digit *tmpa, *tmpb;
toddouska 0:5045d2638c29 216
toddouska 0:5045d2638c29 217 /* pointer aliases */
toddouska 0:5045d2638c29 218
toddouska 0:5045d2638c29 219 /* source */
toddouska 0:5045d2638c29 220 tmpa = a->dp;
toddouska 0:5045d2638c29 221
toddouska 0:5045d2638c29 222 /* destination */
toddouska 0:5045d2638c29 223 tmpb = b->dp;
toddouska 0:5045d2638c29 224
toddouska 0:5045d2638c29 225 /* copy all the digits */
toddouska 0:5045d2638c29 226 for (n = 0; n < a->used; n++) {
toddouska 0:5045d2638c29 227 *tmpb++ = *tmpa++;
toddouska 0:5045d2638c29 228 }
toddouska 0:5045d2638c29 229
toddouska 0:5045d2638c29 230 /* clear high digits */
toddouska 0:5045d2638c29 231 for (; n < b->used; n++) {
toddouska 0:5045d2638c29 232 *tmpb++ = 0;
toddouska 0:5045d2638c29 233 }
toddouska 0:5045d2638c29 234 }
toddouska 0:5045d2638c29 235
toddouska 0:5045d2638c29 236 /* copy used count and sign */
toddouska 0:5045d2638c29 237 b->used = a->used;
toddouska 0:5045d2638c29 238 b->sign = a->sign;
toddouska 0:5045d2638c29 239 return MP_OKAY;
toddouska 0:5045d2638c29 240 }
toddouska 0:5045d2638c29 241
toddouska 0:5045d2638c29 242
toddouska 0:5045d2638c29 243 /* grow as required */
toddouska 0:5045d2638c29 244 int mp_grow (mp_int * a, int size)
toddouska 0:5045d2638c29 245 {
toddouska 0:5045d2638c29 246 int i;
toddouska 0:5045d2638c29 247 mp_digit *tmp;
toddouska 0:5045d2638c29 248
toddouska 0:5045d2638c29 249 /* if the alloc size is smaller alloc more ram */
toddouska 0:5045d2638c29 250 if (a->alloc < size) {
toddouska 0:5045d2638c29 251 /* ensure there are always at least MP_PREC digits extra on top */
toddouska 0:5045d2638c29 252 size += (MP_PREC * 2) - (size % MP_PREC);
toddouska 0:5045d2638c29 253
toddouska 0:5045d2638c29 254 /* reallocate the array a->dp
toddouska 0:5045d2638c29 255 *
toddouska 0:5045d2638c29 256 * We store the return in a temporary variable
toddouska 0:5045d2638c29 257 * in case the operation failed we don't want
toddouska 0:5045d2638c29 258 * to overwrite the dp member of a.
toddouska 0:5045d2638c29 259 */
toddouska 0:5045d2638c29 260 tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size, 0,
toddouska 0:5045d2638c29 261 DYNAMIC_TYPE_BIGINT);
toddouska 0:5045d2638c29 262 if (tmp == NULL) {
toddouska 0:5045d2638c29 263 /* reallocation failed but "a" is still valid [can be freed] */
toddouska 0:5045d2638c29 264 return MP_MEM;
toddouska 0:5045d2638c29 265 }
toddouska 0:5045d2638c29 266
toddouska 0:5045d2638c29 267 /* reallocation succeeded so set a->dp */
toddouska 0:5045d2638c29 268 a->dp = tmp;
toddouska 0:5045d2638c29 269
toddouska 0:5045d2638c29 270 /* zero excess digits */
toddouska 0:5045d2638c29 271 i = a->alloc;
toddouska 0:5045d2638c29 272 a->alloc = size;
toddouska 0:5045d2638c29 273 for (; i < a->alloc; i++) {
toddouska 0:5045d2638c29 274 a->dp[i] = 0;
toddouska 0:5045d2638c29 275 }
toddouska 0:5045d2638c29 276 }
toddouska 0:5045d2638c29 277 return MP_OKAY;
toddouska 0:5045d2638c29 278 }
toddouska 0:5045d2638c29 279
toddouska 0:5045d2638c29 280
toddouska 0:5045d2638c29 281 /* reverse an array, used for radix code */
toddouska 0:5045d2638c29 282 void
toddouska 0:5045d2638c29 283 bn_reverse (unsigned char *s, int len)
toddouska 0:5045d2638c29 284 {
toddouska 0:5045d2638c29 285 int ix, iy;
toddouska 0:5045d2638c29 286 unsigned char t;
toddouska 0:5045d2638c29 287
toddouska 0:5045d2638c29 288 ix = 0;
toddouska 0:5045d2638c29 289 iy = len - 1;
toddouska 0:5045d2638c29 290 while (ix < iy) {
toddouska 0:5045d2638c29 291 t = s[ix];
toddouska 0:5045d2638c29 292 s[ix] = s[iy];
toddouska 0:5045d2638c29 293 s[iy] = t;
toddouska 0:5045d2638c29 294 ++ix;
toddouska 0:5045d2638c29 295 --iy;
toddouska 0:5045d2638c29 296 }
toddouska 0:5045d2638c29 297 }
toddouska 0:5045d2638c29 298
toddouska 0:5045d2638c29 299
toddouska 0:5045d2638c29 300 /* shift right by a certain bit count (store quotient in c, optional
toddouska 0:5045d2638c29 301 remainder in d) */
toddouska 0:5045d2638c29 302 int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
toddouska 0:5045d2638c29 303 {
toddouska 0:5045d2638c29 304 mp_digit D, r, rr;
toddouska 0:5045d2638c29 305 int x, res;
toddouska 0:5045d2638c29 306 mp_int t;
toddouska 0:5045d2638c29 307
toddouska 0:5045d2638c29 308
toddouska 0:5045d2638c29 309 /* if the shift count is <= 0 then we do no work */
toddouska 0:5045d2638c29 310 if (b <= 0) {
toddouska 0:5045d2638c29 311 res = mp_copy (a, c);
toddouska 0:5045d2638c29 312 if (d != NULL) {
toddouska 0:5045d2638c29 313 mp_zero (d);
toddouska 0:5045d2638c29 314 }
toddouska 0:5045d2638c29 315 return res;
toddouska 0:5045d2638c29 316 }
toddouska 0:5045d2638c29 317
toddouska 0:5045d2638c29 318 if ((res = mp_init (&t)) != MP_OKAY) {
toddouska 0:5045d2638c29 319 return res;
toddouska 0:5045d2638c29 320 }
toddouska 0:5045d2638c29 321
toddouska 0:5045d2638c29 322 /* get the remainder */
toddouska 0:5045d2638c29 323 if (d != NULL) {
toddouska 0:5045d2638c29 324 if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
toddouska 0:5045d2638c29 325 mp_clear (&t);
toddouska 0:5045d2638c29 326 return res;
toddouska 0:5045d2638c29 327 }
toddouska 0:5045d2638c29 328 }
toddouska 0:5045d2638c29 329
toddouska 0:5045d2638c29 330 /* copy */
toddouska 0:5045d2638c29 331 if ((res = mp_copy (a, c)) != MP_OKAY) {
toddouska 0:5045d2638c29 332 mp_clear (&t);
toddouska 0:5045d2638c29 333 return res;
toddouska 0:5045d2638c29 334 }
toddouska 0:5045d2638c29 335
toddouska 0:5045d2638c29 336 /* shift by as many digits in the bit count */
toddouska 0:5045d2638c29 337 if (b >= (int)DIGIT_BIT) {
toddouska 0:5045d2638c29 338 mp_rshd (c, b / DIGIT_BIT);
toddouska 0:5045d2638c29 339 }
toddouska 0:5045d2638c29 340
toddouska 0:5045d2638c29 341 /* shift any bit count < DIGIT_BIT */
toddouska 0:5045d2638c29 342 D = (mp_digit) (b % DIGIT_BIT);
toddouska 0:5045d2638c29 343 if (D != 0) {
toddouska 0:5045d2638c29 344 register mp_digit *tmpc, mask, shift;
toddouska 0:5045d2638c29 345
toddouska 0:5045d2638c29 346 /* mask */
toddouska 0:5045d2638c29 347 mask = (((mp_digit)1) << D) - 1;
toddouska 0:5045d2638c29 348
toddouska 0:5045d2638c29 349 /* shift for lsb */
toddouska 0:5045d2638c29 350 shift = DIGIT_BIT - D;
toddouska 0:5045d2638c29 351
toddouska 0:5045d2638c29 352 /* alias */
toddouska 0:5045d2638c29 353 tmpc = c->dp + (c->used - 1);
toddouska 0:5045d2638c29 354
toddouska 0:5045d2638c29 355 /* carry */
toddouska 0:5045d2638c29 356 r = 0;
toddouska 0:5045d2638c29 357 for (x = c->used - 1; x >= 0; x--) {
toddouska 0:5045d2638c29 358 /* get the lower bits of this word in a temp */
toddouska 0:5045d2638c29 359 rr = *tmpc & mask;
toddouska 0:5045d2638c29 360
toddouska 0:5045d2638c29 361 /* shift the current word and mix in the carry bits from the previous
toddouska 0:5045d2638c29 362 word */
toddouska 0:5045d2638c29 363 *tmpc = (*tmpc >> D) | (r << shift);
toddouska 0:5045d2638c29 364 --tmpc;
toddouska 0:5045d2638c29 365
toddouska 0:5045d2638c29 366 /* set the carry to the carry bits of the current word found above */
toddouska 0:5045d2638c29 367 r = rr;
toddouska 0:5045d2638c29 368 }
toddouska 0:5045d2638c29 369 }
toddouska 0:5045d2638c29 370 mp_clamp (c);
toddouska 0:5045d2638c29 371 if (d != NULL) {
toddouska 0:5045d2638c29 372 mp_exch (&t, d);
toddouska 0:5045d2638c29 373 }
toddouska 0:5045d2638c29 374 mp_clear (&t);
toddouska 0:5045d2638c29 375 return MP_OKAY;
toddouska 0:5045d2638c29 376 }
toddouska 0:5045d2638c29 377
toddouska 0:5045d2638c29 378
toddouska 0:5045d2638c29 379 /* set to zero */
toddouska 0:5045d2638c29 380 void mp_zero (mp_int * a)
toddouska 0:5045d2638c29 381 {
toddouska 0:5045d2638c29 382 int n;
toddouska 0:5045d2638c29 383 mp_digit *tmp;
toddouska 0:5045d2638c29 384
toddouska 0:5045d2638c29 385 a->sign = MP_ZPOS;
toddouska 0:5045d2638c29 386 a->used = 0;
toddouska 0:5045d2638c29 387
toddouska 0:5045d2638c29 388 tmp = a->dp;
toddouska 0:5045d2638c29 389 for (n = 0; n < a->alloc; n++) {
toddouska 0:5045d2638c29 390 *tmp++ = 0;
toddouska 0:5045d2638c29 391 }
toddouska 0:5045d2638c29 392 }
toddouska 0:5045d2638c29 393
toddouska 0:5045d2638c29 394
toddouska 0:5045d2638c29 395 /* trim unused digits
toddouska 0:5045d2638c29 396 *
toddouska 0:5045d2638c29 397 * This is used to ensure that leading zero digits are
toddouska 0:5045d2638c29 398 * trimed and the leading "used" digit will be non-zero
toddouska 0:5045d2638c29 399 * Typically very fast. Also fixes the sign if there
toddouska 0:5045d2638c29 400 * are no more leading digits
toddouska 0:5045d2638c29 401 */
toddouska 0:5045d2638c29 402 void
toddouska 0:5045d2638c29 403 mp_clamp (mp_int * a)
toddouska 0:5045d2638c29 404 {
toddouska 0:5045d2638c29 405 /* decrease used while the most significant digit is
toddouska 0:5045d2638c29 406 * zero.
toddouska 0:5045d2638c29 407 */
toddouska 0:5045d2638c29 408 while (a->used > 0 && a->dp[a->used - 1] == 0) {
toddouska 0:5045d2638c29 409 --(a->used);
toddouska 0:5045d2638c29 410 }
toddouska 0:5045d2638c29 411
toddouska 0:5045d2638c29 412 /* reset the sign flag if used == 0 */
toddouska 0:5045d2638c29 413 if (a->used == 0) {
toddouska 0:5045d2638c29 414 a->sign = MP_ZPOS;
toddouska 0:5045d2638c29 415 }
toddouska 0:5045d2638c29 416 }
toddouska 0:5045d2638c29 417
toddouska 0:5045d2638c29 418
toddouska 0:5045d2638c29 419 /* swap the elements of two integers, for cases where you can't simply swap the
toddouska 0:5045d2638c29 420 * mp_int pointers around
toddouska 0:5045d2638c29 421 */
toddouska 0:5045d2638c29 422 void
toddouska 0:5045d2638c29 423 mp_exch (mp_int * a, mp_int * b)
toddouska 0:5045d2638c29 424 {
toddouska 0:5045d2638c29 425 mp_int t;
toddouska 0:5045d2638c29 426
toddouska 0:5045d2638c29 427 t = *a;
toddouska 0:5045d2638c29 428 *a = *b;
toddouska 0:5045d2638c29 429 *b = t;
toddouska 0:5045d2638c29 430 }
toddouska 0:5045d2638c29 431
toddouska 0:5045d2638c29 432
toddouska 0:5045d2638c29 433 /* shift right a certain amount of digits */
toddouska 0:5045d2638c29 434 void mp_rshd (mp_int * a, int b)
toddouska 0:5045d2638c29 435 {
toddouska 0:5045d2638c29 436 int x;
toddouska 0:5045d2638c29 437
toddouska 0:5045d2638c29 438 /* if b <= 0 then ignore it */
toddouska 0:5045d2638c29 439 if (b <= 0) {
toddouska 0:5045d2638c29 440 return;
toddouska 0:5045d2638c29 441 }
toddouska 0:5045d2638c29 442
toddouska 0:5045d2638c29 443 /* if b > used then simply zero it and return */
toddouska 0:5045d2638c29 444 if (a->used <= b) {
toddouska 0:5045d2638c29 445 mp_zero (a);
toddouska 0:5045d2638c29 446 return;
toddouska 0:5045d2638c29 447 }
toddouska 0:5045d2638c29 448
toddouska 0:5045d2638c29 449 {
toddouska 0:5045d2638c29 450 register mp_digit *bottom, *top;
toddouska 0:5045d2638c29 451
toddouska 0:5045d2638c29 452 /* shift the digits down */
toddouska 0:5045d2638c29 453
toddouska 0:5045d2638c29 454 /* bottom */
toddouska 0:5045d2638c29 455 bottom = a->dp;
toddouska 0:5045d2638c29 456
toddouska 0:5045d2638c29 457 /* top [offset into digits] */
toddouska 0:5045d2638c29 458 top = a->dp + b;
toddouska 0:5045d2638c29 459
toddouska 0:5045d2638c29 460 /* this is implemented as a sliding window where
toddouska 0:5045d2638c29 461 * the window is b-digits long and digits from
toddouska 0:5045d2638c29 462 * the top of the window are copied to the bottom
toddouska 0:5045d2638c29 463 *
toddouska 0:5045d2638c29 464 * e.g.
toddouska 0:5045d2638c29 465
toddouska 0:5045d2638c29 466 b-2 | b-1 | b0 | b1 | b2 | ... | bb | ---->
toddouska 0:5045d2638c29 467 /\ | ---->
toddouska 0:5045d2638c29 468 \-------------------/ ---->
toddouska 0:5045d2638c29 469 */
toddouska 0:5045d2638c29 470 for (x = 0; x < (a->used - b); x++) {
toddouska 0:5045d2638c29 471 *bottom++ = *top++;
toddouska 0:5045d2638c29 472 }
toddouska 0:5045d2638c29 473
toddouska 0:5045d2638c29 474 /* zero the top digits */
toddouska 0:5045d2638c29 475 for (; x < a->used; x++) {
toddouska 0:5045d2638c29 476 *bottom++ = 0;
toddouska 0:5045d2638c29 477 }
toddouska 0:5045d2638c29 478 }
toddouska 0:5045d2638c29 479
toddouska 0:5045d2638c29 480 /* remove excess digits */
toddouska 0:5045d2638c29 481 a->used -= b;
toddouska 0:5045d2638c29 482 }
toddouska 0:5045d2638c29 483
toddouska 0:5045d2638c29 484
toddouska 0:5045d2638c29 485 /* calc a value mod 2**b */
toddouska 0:5045d2638c29 486 int
toddouska 0:5045d2638c29 487 mp_mod_2d (mp_int * a, int b, mp_int * c)
toddouska 0:5045d2638c29 488 {
toddouska 0:5045d2638c29 489 int x, res;
toddouska 0:5045d2638c29 490
toddouska 0:5045d2638c29 491 /* if b is <= 0 then zero the int */
toddouska 0:5045d2638c29 492 if (b <= 0) {
toddouska 0:5045d2638c29 493 mp_zero (c);
toddouska 0:5045d2638c29 494 return MP_OKAY;
toddouska 0:5045d2638c29 495 }
toddouska 0:5045d2638c29 496
toddouska 0:5045d2638c29 497 /* if the modulus is larger than the value than return */
toddouska 0:5045d2638c29 498 if (b >= (int) (a->used * DIGIT_BIT)) {
toddouska 0:5045d2638c29 499 res = mp_copy (a, c);
toddouska 0:5045d2638c29 500 return res;
toddouska 0:5045d2638c29 501 }
toddouska 0:5045d2638c29 502
toddouska 0:5045d2638c29 503 /* copy */
toddouska 0:5045d2638c29 504 if ((res = mp_copy (a, c)) != MP_OKAY) {
toddouska 0:5045d2638c29 505 return res;
toddouska 0:5045d2638c29 506 }
toddouska 0:5045d2638c29 507
toddouska 0:5045d2638c29 508 /* zero digits above the last digit of the modulus */
toddouska 0:5045d2638c29 509 for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
toddouska 0:5045d2638c29 510 c->dp[x] = 0;
toddouska 0:5045d2638c29 511 }
toddouska 0:5045d2638c29 512 /* clear the digit that is not completely outside/inside the modulus */
toddouska 0:5045d2638c29 513 c->dp[b / DIGIT_BIT] &= (mp_digit) ((((mp_digit) 1) <<
toddouska 0:5045d2638c29 514 (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1));
toddouska 0:5045d2638c29 515 mp_clamp (c);
toddouska 0:5045d2638c29 516 return MP_OKAY;
toddouska 0:5045d2638c29 517 }
toddouska 0:5045d2638c29 518
toddouska 0:5045d2638c29 519
toddouska 0:5045d2638c29 520 /* reads a unsigned char array, assumes the msb is stored first [big endian] */
toddouska 0:5045d2638c29 521 int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
toddouska 0:5045d2638c29 522 {
toddouska 0:5045d2638c29 523 int res;
toddouska 0:5045d2638c29 524
toddouska 0:5045d2638c29 525 /* make sure there are at least two digits */
toddouska 0:5045d2638c29 526 if (a->alloc < 2) {
toddouska 0:5045d2638c29 527 if ((res = mp_grow(a, 2)) != MP_OKAY) {
toddouska 0:5045d2638c29 528 return res;
toddouska 0:5045d2638c29 529 }
toddouska 0:5045d2638c29 530 }
toddouska 0:5045d2638c29 531
toddouska 0:5045d2638c29 532 /* zero the int */
toddouska 0:5045d2638c29 533 mp_zero (a);
toddouska 0:5045d2638c29 534
toddouska 0:5045d2638c29 535 /* read the bytes in */
toddouska 0:5045d2638c29 536 while (c-- > 0) {
toddouska 0:5045d2638c29 537 if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
toddouska 0:5045d2638c29 538 return res;
toddouska 0:5045d2638c29 539 }
toddouska 0:5045d2638c29 540
toddouska 0:5045d2638c29 541 #ifndef MP_8BIT
toddouska 0:5045d2638c29 542 a->dp[0] |= *b++;
toddouska 0:5045d2638c29 543 a->used += 1;
toddouska 0:5045d2638c29 544 #else
toddouska 0:5045d2638c29 545 a->dp[0] = (*b & MP_MASK);
toddouska 0:5045d2638c29 546 a->dp[1] |= ((*b++ >> 7U) & 1);
toddouska 0:5045d2638c29 547 a->used += 2;
toddouska 0:5045d2638c29 548 #endif
toddouska 0:5045d2638c29 549 }
toddouska 0:5045d2638c29 550 mp_clamp (a);
toddouska 0:5045d2638c29 551 return MP_OKAY;
toddouska 0:5045d2638c29 552 }
toddouska 0:5045d2638c29 553
toddouska 0:5045d2638c29 554
toddouska 0:5045d2638c29 555 /* shift left by a certain bit count */
toddouska 0:5045d2638c29 556 int mp_mul_2d (mp_int * a, int b, mp_int * c)
toddouska 0:5045d2638c29 557 {
toddouska 0:5045d2638c29 558 mp_digit d;
toddouska 0:5045d2638c29 559 int res;
toddouska 0:5045d2638c29 560
toddouska 0:5045d2638c29 561 /* copy */
toddouska 0:5045d2638c29 562 if (a != c) {
toddouska 0:5045d2638c29 563 if ((res = mp_copy (a, c)) != MP_OKAY) {
toddouska 0:5045d2638c29 564 return res;
toddouska 0:5045d2638c29 565 }
toddouska 0:5045d2638c29 566 }
toddouska 0:5045d2638c29 567
toddouska 0:5045d2638c29 568 if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) {
toddouska 0:5045d2638c29 569 if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
toddouska 0:5045d2638c29 570 return res;
toddouska 0:5045d2638c29 571 }
toddouska 0:5045d2638c29 572 }
toddouska 0:5045d2638c29 573
toddouska 0:5045d2638c29 574 /* shift by as many digits in the bit count */
toddouska 0:5045d2638c29 575 if (b >= (int)DIGIT_BIT) {
toddouska 0:5045d2638c29 576 if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
toddouska 0:5045d2638c29 577 return res;
toddouska 0:5045d2638c29 578 }
toddouska 0:5045d2638c29 579 }
toddouska 0:5045d2638c29 580
toddouska 0:5045d2638c29 581 /* shift any bit count < DIGIT_BIT */
toddouska 0:5045d2638c29 582 d = (mp_digit) (b % DIGIT_BIT);
toddouska 0:5045d2638c29 583 if (d != 0) {
toddouska 0:5045d2638c29 584 register mp_digit *tmpc, shift, mask, r, rr;
toddouska 0:5045d2638c29 585 register int x;
toddouska 0:5045d2638c29 586
toddouska 0:5045d2638c29 587 /* bitmask for carries */
toddouska 0:5045d2638c29 588 mask = (((mp_digit)1) << d) - 1;
toddouska 0:5045d2638c29 589
toddouska 0:5045d2638c29 590 /* shift for msbs */
toddouska 0:5045d2638c29 591 shift = DIGIT_BIT - d;
toddouska 0:5045d2638c29 592
toddouska 0:5045d2638c29 593 /* alias */
toddouska 0:5045d2638c29 594 tmpc = c->dp;
toddouska 0:5045d2638c29 595
toddouska 0:5045d2638c29 596 /* carry */
toddouska 0:5045d2638c29 597 r = 0;
toddouska 0:5045d2638c29 598 for (x = 0; x < c->used; x++) {
toddouska 0:5045d2638c29 599 /* get the higher bits of the current word */
toddouska 0:5045d2638c29 600 rr = (*tmpc >> shift) & mask;
toddouska 0:5045d2638c29 601
toddouska 0:5045d2638c29 602 /* shift the current word and OR in the carry */
toddouska 0:5045d2638c29 603 *tmpc = ((*tmpc << d) | r) & MP_MASK;
toddouska 0:5045d2638c29 604 ++tmpc;
toddouska 0:5045d2638c29 605
toddouska 0:5045d2638c29 606 /* set the carry to the carry bits of the current word */
toddouska 0:5045d2638c29 607 r = rr;
toddouska 0:5045d2638c29 608 }
toddouska 0:5045d2638c29 609
toddouska 0:5045d2638c29 610 /* set final carry */
toddouska 0:5045d2638c29 611 if (r != 0) {
toddouska 0:5045d2638c29 612 c->dp[(c->used)++] = r;
toddouska 0:5045d2638c29 613 }
toddouska 0:5045d2638c29 614 }
toddouska 0:5045d2638c29 615 mp_clamp (c);
toddouska 0:5045d2638c29 616 return MP_OKAY;
toddouska 0:5045d2638c29 617 }
toddouska 0:5045d2638c29 618
toddouska 0:5045d2638c29 619
toddouska 0:5045d2638c29 620 /* shift left a certain amount of digits */
toddouska 0:5045d2638c29 621 int mp_lshd (mp_int * a, int b)
toddouska 0:5045d2638c29 622 {
toddouska 0:5045d2638c29 623 int x, res;
toddouska 0:5045d2638c29 624
toddouska 0:5045d2638c29 625 /* if its less than zero return */
toddouska 0:5045d2638c29 626 if (b <= 0) {
toddouska 0:5045d2638c29 627 return MP_OKAY;
toddouska 0:5045d2638c29 628 }
toddouska 0:5045d2638c29 629
toddouska 0:5045d2638c29 630 /* grow to fit the new digits */
toddouska 0:5045d2638c29 631 if (a->alloc < a->used + b) {
toddouska 0:5045d2638c29 632 if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
toddouska 0:5045d2638c29 633 return res;
toddouska 0:5045d2638c29 634 }
toddouska 0:5045d2638c29 635 }
toddouska 0:5045d2638c29 636
toddouska 0:5045d2638c29 637 {
toddouska 0:5045d2638c29 638 register mp_digit *top, *bottom;
toddouska 0:5045d2638c29 639
toddouska 0:5045d2638c29 640 /* increment the used by the shift amount then copy upwards */
toddouska 0:5045d2638c29 641 a->used += b;
toddouska 0:5045d2638c29 642
toddouska 0:5045d2638c29 643 /* top */
toddouska 0:5045d2638c29 644 top = a->dp + a->used - 1;
toddouska 0:5045d2638c29 645
toddouska 0:5045d2638c29 646 /* base */
toddouska 0:5045d2638c29 647 bottom = a->dp + a->used - 1 - b;
toddouska 0:5045d2638c29 648
toddouska 0:5045d2638c29 649 /* much like mp_rshd this is implemented using a sliding window
toddouska 0:5045d2638c29 650 * except the window goes the otherway around. Copying from
toddouska 0:5045d2638c29 651 * the bottom to the top. see bn_mp_rshd.c for more info.
toddouska 0:5045d2638c29 652 */
toddouska 0:5045d2638c29 653 for (x = a->used - 1; x >= b; x--) {
toddouska 0:5045d2638c29 654 *top-- = *bottom--;
toddouska 0:5045d2638c29 655 }
toddouska 0:5045d2638c29 656
toddouska 0:5045d2638c29 657 /* zero the lower digits */
toddouska 0:5045d2638c29 658 top = a->dp;
toddouska 0:5045d2638c29 659 for (x = 0; x < b; x++) {
toddouska 0:5045d2638c29 660 *top++ = 0;
toddouska 0:5045d2638c29 661 }
toddouska 0:5045d2638c29 662 }
toddouska 0:5045d2638c29 663 return MP_OKAY;
toddouska 0:5045d2638c29 664 }
toddouska 0:5045d2638c29 665
toddouska 0:5045d2638c29 666
toddouska 0:5045d2638c29 667 /* this is a shell function that calls either the normal or Montgomery
toddouska 0:5045d2638c29 668 * exptmod functions. Originally the call to the montgomery code was
toddouska 0:5045d2638c29 669 * embedded in the normal function but that wasted alot of stack space
toddouska 0:5045d2638c29 670 * for nothing (since 99% of the time the Montgomery code would be called)
toddouska 0:5045d2638c29 671 */
toddouska 0:5045d2638c29 672 int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
toddouska 0:5045d2638c29 673 {
toddouska 0:5045d2638c29 674 int dr;
toddouska 0:5045d2638c29 675
toddouska 0:5045d2638c29 676 /* modulus P must be positive */
toddouska 0:5045d2638c29 677 if (P->sign == MP_NEG) {
toddouska 0:5045d2638c29 678 return MP_VAL;
toddouska 0:5045d2638c29 679 }
toddouska 0:5045d2638c29 680
toddouska 0:5045d2638c29 681 /* if exponent X is negative we have to recurse */
toddouska 0:5045d2638c29 682 if (X->sign == MP_NEG) {
toddouska 0:5045d2638c29 683 #ifdef BN_MP_INVMOD_C
toddouska 0:5045d2638c29 684 mp_int tmpG, tmpX;
toddouska 0:5045d2638c29 685 int err;
toddouska 0:5045d2638c29 686
toddouska 0:5045d2638c29 687 /* first compute 1/G mod P */
toddouska 0:5045d2638c29 688 if ((err = mp_init(&tmpG)) != MP_OKAY) {
toddouska 0:5045d2638c29 689 return err;
toddouska 0:5045d2638c29 690 }
toddouska 0:5045d2638c29 691 if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
toddouska 0:5045d2638c29 692 mp_clear(&tmpG);
toddouska 0:5045d2638c29 693 return err;
toddouska 0:5045d2638c29 694 }
toddouska 0:5045d2638c29 695
toddouska 0:5045d2638c29 696 /* now get |X| */
toddouska 0:5045d2638c29 697 if ((err = mp_init(&tmpX)) != MP_OKAY) {
toddouska 0:5045d2638c29 698 mp_clear(&tmpG);
toddouska 0:5045d2638c29 699 return err;
toddouska 0:5045d2638c29 700 }
toddouska 0:5045d2638c29 701 if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
toddouska 0:5045d2638c29 702 mp_clear(&tmpG);
toddouska 0:5045d2638c29 703 mp_clear(&tmpX);
toddouska 0:5045d2638c29 704 return err;
toddouska 0:5045d2638c29 705 }
toddouska 0:5045d2638c29 706
toddouska 0:5045d2638c29 707 /* and now compute (1/G)**|X| instead of G**X [X < 0] */
toddouska 0:5045d2638c29 708 err = mp_exptmod(&tmpG, &tmpX, P, Y);
toddouska 0:5045d2638c29 709 mp_clear(&tmpG);
toddouska 0:5045d2638c29 710 mp_clear(&tmpX);
toddouska 0:5045d2638c29 711 return err;
toddouska 0:5045d2638c29 712 #else
toddouska 0:5045d2638c29 713 /* no invmod */
toddouska 0:5045d2638c29 714 return MP_VAL;
toddouska 0:5045d2638c29 715 #endif
toddouska 0:5045d2638c29 716 }
toddouska 0:5045d2638c29 717
toddouska 0:5045d2638c29 718 /* modified diminished radix reduction */
toddouska 0:5045d2638c29 719 #if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && \
toddouska 0:5045d2638c29 720 defined(BN_S_MP_EXPTMOD_C)
toddouska 0:5045d2638c29 721 if (mp_reduce_is_2k_l(P) == MP_YES) {
toddouska 0:5045d2638c29 722 return s_mp_exptmod(G, X, P, Y, 1);
toddouska 0:5045d2638c29 723 }
toddouska 0:5045d2638c29 724 #endif
toddouska 0:5045d2638c29 725
toddouska 0:5045d2638c29 726 #ifdef BN_MP_DR_IS_MODULUS_C
toddouska 0:5045d2638c29 727 /* is it a DR modulus? */
toddouska 0:5045d2638c29 728 dr = mp_dr_is_modulus(P);
toddouska 0:5045d2638c29 729 #else
toddouska 0:5045d2638c29 730 /* default to no */
toddouska 0:5045d2638c29 731 dr = 0;
toddouska 0:5045d2638c29 732 #endif
toddouska 0:5045d2638c29 733
toddouska 0:5045d2638c29 734 #ifdef BN_MP_REDUCE_IS_2K_C
toddouska 0:5045d2638c29 735 /* if not, is it a unrestricted DR modulus? */
toddouska 0:5045d2638c29 736 if (dr == 0) {
toddouska 0:5045d2638c29 737 dr = mp_reduce_is_2k(P) << 1;
toddouska 0:5045d2638c29 738 }
toddouska 0:5045d2638c29 739 #endif
toddouska 0:5045d2638c29 740
toddouska 0:5045d2638c29 741 /* if the modulus is odd or dr != 0 use the montgomery method */
toddouska 0:5045d2638c29 742 #ifdef BN_MP_EXPTMOD_FAST_C
toddouska 0:5045d2638c29 743 if (mp_isodd (P) == 1 || dr != 0) {
toddouska 0:5045d2638c29 744 return mp_exptmod_fast (G, X, P, Y, dr);
toddouska 0:5045d2638c29 745 } else {
toddouska 0:5045d2638c29 746 #endif
toddouska 0:5045d2638c29 747 #ifdef BN_S_MP_EXPTMOD_C
toddouska 0:5045d2638c29 748 /* otherwise use the generic Barrett reduction technique */
toddouska 0:5045d2638c29 749 return s_mp_exptmod (G, X, P, Y, 0);
toddouska 0:5045d2638c29 750 #else
toddouska 0:5045d2638c29 751 /* no exptmod for evens */
toddouska 0:5045d2638c29 752 return MP_VAL;
toddouska 0:5045d2638c29 753 #endif
toddouska 0:5045d2638c29 754 #ifdef BN_MP_EXPTMOD_FAST_C
toddouska 0:5045d2638c29 755 }
toddouska 0:5045d2638c29 756 #endif
toddouska 0:5045d2638c29 757 }
toddouska 0:5045d2638c29 758
toddouska 0:5045d2638c29 759
toddouska 0:5045d2638c29 760 /* b = |a|
toddouska 0:5045d2638c29 761 *
toddouska 0:5045d2638c29 762 * Simple function copies the input and fixes the sign to positive
toddouska 0:5045d2638c29 763 */
toddouska 0:5045d2638c29 764 int
toddouska 0:5045d2638c29 765 mp_abs (mp_int * a, mp_int * b)
toddouska 0:5045d2638c29 766 {
toddouska 0:5045d2638c29 767 int res;
toddouska 0:5045d2638c29 768
toddouska 0:5045d2638c29 769 /* copy a to b */
toddouska 0:5045d2638c29 770 if (a != b) {
toddouska 0:5045d2638c29 771 if ((res = mp_copy (a, b)) != MP_OKAY) {
toddouska 0:5045d2638c29 772 return res;
toddouska 0:5045d2638c29 773 }
toddouska 0:5045d2638c29 774 }
toddouska 0:5045d2638c29 775
toddouska 0:5045d2638c29 776 /* force the sign of b to positive */
toddouska 0:5045d2638c29 777 b->sign = MP_ZPOS;
toddouska 0:5045d2638c29 778
toddouska 0:5045d2638c29 779 return MP_OKAY;
toddouska 0:5045d2638c29 780 }
toddouska 0:5045d2638c29 781
toddouska 0:5045d2638c29 782
toddouska 0:5045d2638c29 783 /* hac 14.61, pp608 */
toddouska 0:5045d2638c29 784 int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
toddouska 0:5045d2638c29 785 {
toddouska 0:5045d2638c29 786 /* b cannot be negative */
toddouska 0:5045d2638c29 787 if (b->sign == MP_NEG || mp_iszero(b) == 1) {
toddouska 0:5045d2638c29 788 return MP_VAL;
toddouska 0:5045d2638c29 789 }
toddouska 0:5045d2638c29 790
toddouska 0:5045d2638c29 791 #ifdef BN_FAST_MP_INVMOD_C
toddouska 0:5045d2638c29 792 /* if the modulus is odd we can use a faster routine instead */
toddouska 0:5045d2638c29 793 if (mp_isodd (b) == 1) {
toddouska 0:5045d2638c29 794 return fast_mp_invmod (a, b, c);
toddouska 0:5045d2638c29 795 }
toddouska 0:5045d2638c29 796 #endif
toddouska 0:5045d2638c29 797
toddouska 0:5045d2638c29 798 #ifdef BN_MP_INVMOD_SLOW_C
toddouska 0:5045d2638c29 799 return mp_invmod_slow(a, b, c);
toddouska 0:5045d2638c29 800 #endif
toddouska 0:5045d2638c29 801 }
toddouska 0:5045d2638c29 802
toddouska 0:5045d2638c29 803
toddouska 0:5045d2638c29 804 /* computes the modular inverse via binary extended euclidean algorithm,
toddouska 0:5045d2638c29 805 * that is c = 1/a mod b
toddouska 0:5045d2638c29 806 *
toddouska 0:5045d2638c29 807 * Based on slow invmod except this is optimized for the case where b is
toddouska 0:5045d2638c29 808 * odd as per HAC Note 14.64 on pp. 610
toddouska 0:5045d2638c29 809 */
toddouska 0:5045d2638c29 810 int fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c)
toddouska 0:5045d2638c29 811 {
toddouska 0:5045d2638c29 812 mp_int x, y, u, v, B, D;
toddouska 0:5045d2638c29 813 int res, neg;
toddouska 0:5045d2638c29 814
toddouska 0:5045d2638c29 815 /* 2. [modified] b must be odd */
toddouska 0:5045d2638c29 816 if (mp_iseven (b) == 1) {
toddouska 0:5045d2638c29 817 return MP_VAL;
toddouska 0:5045d2638c29 818 }
toddouska 0:5045d2638c29 819
toddouska 0:5045d2638c29 820 /* init all our temps */
toddouska 0:5045d2638c29 821 if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D)) != MP_OKAY) {
toddouska 0:5045d2638c29 822 return res;
toddouska 0:5045d2638c29 823 }
toddouska 0:5045d2638c29 824
toddouska 0:5045d2638c29 825 /* x == modulus, y == value to invert */
toddouska 0:5045d2638c29 826 if ((res = mp_copy (b, &x)) != MP_OKAY) {
toddouska 0:5045d2638c29 827 goto LBL_ERR;
toddouska 0:5045d2638c29 828 }
toddouska 0:5045d2638c29 829
toddouska 0:5045d2638c29 830 /* we need y = |a| */
toddouska 0:5045d2638c29 831 if ((res = mp_mod (a, b, &y)) != MP_OKAY) {
toddouska 0:5045d2638c29 832 goto LBL_ERR;
toddouska 0:5045d2638c29 833 }
toddouska 0:5045d2638c29 834
toddouska 0:5045d2638c29 835 /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
toddouska 0:5045d2638c29 836 if ((res = mp_copy (&x, &u)) != MP_OKAY) {
toddouska 0:5045d2638c29 837 goto LBL_ERR;
toddouska 0:5045d2638c29 838 }
toddouska 0:5045d2638c29 839 if ((res = mp_copy (&y, &v)) != MP_OKAY) {
toddouska 0:5045d2638c29 840 goto LBL_ERR;
toddouska 0:5045d2638c29 841 }
toddouska 0:5045d2638c29 842 mp_set (&D, 1);
toddouska 0:5045d2638c29 843
toddouska 0:5045d2638c29 844 top:
toddouska 0:5045d2638c29 845 /* 4. while u is even do */
toddouska 0:5045d2638c29 846 while (mp_iseven (&u) == 1) {
toddouska 0:5045d2638c29 847 /* 4.1 u = u/2 */
toddouska 0:5045d2638c29 848 if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
toddouska 0:5045d2638c29 849 goto LBL_ERR;
toddouska 0:5045d2638c29 850 }
toddouska 0:5045d2638c29 851 /* 4.2 if B is odd then */
toddouska 0:5045d2638c29 852 if (mp_isodd (&B) == 1) {
toddouska 0:5045d2638c29 853 if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
toddouska 0:5045d2638c29 854 goto LBL_ERR;
toddouska 0:5045d2638c29 855 }
toddouska 0:5045d2638c29 856 }
toddouska 0:5045d2638c29 857 /* B = B/2 */
toddouska 0:5045d2638c29 858 if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
toddouska 0:5045d2638c29 859 goto LBL_ERR;
toddouska 0:5045d2638c29 860 }
toddouska 0:5045d2638c29 861 }
toddouska 0:5045d2638c29 862
toddouska 0:5045d2638c29 863 /* 5. while v is even do */
toddouska 0:5045d2638c29 864 while (mp_iseven (&v) == 1) {
toddouska 0:5045d2638c29 865 /* 5.1 v = v/2 */
toddouska 0:5045d2638c29 866 if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
toddouska 0:5045d2638c29 867 goto LBL_ERR;
toddouska 0:5045d2638c29 868 }
toddouska 0:5045d2638c29 869 /* 5.2 if D is odd then */
toddouska 0:5045d2638c29 870 if (mp_isodd (&D) == 1) {
toddouska 0:5045d2638c29 871 /* D = (D-x)/2 */
toddouska 0:5045d2638c29 872 if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
toddouska 0:5045d2638c29 873 goto LBL_ERR;
toddouska 0:5045d2638c29 874 }
toddouska 0:5045d2638c29 875 }
toddouska 0:5045d2638c29 876 /* D = D/2 */
toddouska 0:5045d2638c29 877 if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
toddouska 0:5045d2638c29 878 goto LBL_ERR;
toddouska 0:5045d2638c29 879 }
toddouska 0:5045d2638c29 880 }
toddouska 0:5045d2638c29 881
toddouska 0:5045d2638c29 882 /* 6. if u >= v then */
toddouska 0:5045d2638c29 883 if (mp_cmp (&u, &v) != MP_LT) {
toddouska 0:5045d2638c29 884 /* u = u - v, B = B - D */
toddouska 0:5045d2638c29 885 if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
toddouska 0:5045d2638c29 886 goto LBL_ERR;
toddouska 0:5045d2638c29 887 }
toddouska 0:5045d2638c29 888
toddouska 0:5045d2638c29 889 if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
toddouska 0:5045d2638c29 890 goto LBL_ERR;
toddouska 0:5045d2638c29 891 }
toddouska 0:5045d2638c29 892 } else {
toddouska 0:5045d2638c29 893 /* v - v - u, D = D - B */
toddouska 0:5045d2638c29 894 if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
toddouska 0:5045d2638c29 895 goto LBL_ERR;
toddouska 0:5045d2638c29 896 }
toddouska 0:5045d2638c29 897
toddouska 0:5045d2638c29 898 if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
toddouska 0:5045d2638c29 899 goto LBL_ERR;
toddouska 0:5045d2638c29 900 }
toddouska 0:5045d2638c29 901 }
toddouska 0:5045d2638c29 902
toddouska 0:5045d2638c29 903 /* if not zero goto step 4 */
toddouska 0:5045d2638c29 904 if (mp_iszero (&u) == 0) {
toddouska 0:5045d2638c29 905 goto top;
toddouska 0:5045d2638c29 906 }
toddouska 0:5045d2638c29 907
toddouska 0:5045d2638c29 908 /* now a = C, b = D, gcd == g*v */
toddouska 0:5045d2638c29 909
toddouska 0:5045d2638c29 910 /* if v != 1 then there is no inverse */
toddouska 0:5045d2638c29 911 if (mp_cmp_d (&v, 1) != MP_EQ) {
toddouska 0:5045d2638c29 912 res = MP_VAL;
toddouska 0:5045d2638c29 913 goto LBL_ERR;
toddouska 0:5045d2638c29 914 }
toddouska 0:5045d2638c29 915
toddouska 0:5045d2638c29 916 /* b is now the inverse */
toddouska 0:5045d2638c29 917 neg = a->sign;
toddouska 0:5045d2638c29 918 while (D.sign == MP_NEG) {
toddouska 0:5045d2638c29 919 if ((res = mp_add (&D, b, &D)) != MP_OKAY) {
toddouska 0:5045d2638c29 920 goto LBL_ERR;
toddouska 0:5045d2638c29 921 }
toddouska 0:5045d2638c29 922 }
toddouska 0:5045d2638c29 923 mp_exch (&D, c);
toddouska 0:5045d2638c29 924 c->sign = neg;
toddouska 0:5045d2638c29 925 res = MP_OKAY;
toddouska 0:5045d2638c29 926
toddouska 0:5045d2638c29 927 LBL_ERR:mp_clear(&x);
toddouska 0:5045d2638c29 928 mp_clear(&y);
toddouska 0:5045d2638c29 929 mp_clear(&u);
toddouska 0:5045d2638c29 930 mp_clear(&v);
toddouska 0:5045d2638c29 931 mp_clear(&B);
toddouska 0:5045d2638c29 932 mp_clear(&D);
toddouska 0:5045d2638c29 933 return res;
toddouska 0:5045d2638c29 934 }
toddouska 0:5045d2638c29 935
toddouska 0:5045d2638c29 936
toddouska 0:5045d2638c29 937 /* hac 14.61, pp608 */
toddouska 0:5045d2638c29 938 int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
toddouska 0:5045d2638c29 939 {
toddouska 0:5045d2638c29 940 mp_int x, y, u, v, A, B, C, D;
toddouska 0:5045d2638c29 941 int res;
toddouska 0:5045d2638c29 942
toddouska 0:5045d2638c29 943 /* b cannot be negative */
toddouska 0:5045d2638c29 944 if (b->sign == MP_NEG || mp_iszero(b) == 1) {
toddouska 0:5045d2638c29 945 return MP_VAL;
toddouska 0:5045d2638c29 946 }
toddouska 0:5045d2638c29 947
toddouska 0:5045d2638c29 948 /* init temps */
toddouska 0:5045d2638c29 949 if ((res = mp_init_multi(&x, &y, &u, &v,
toddouska 0:5045d2638c29 950 &A, &B)) != MP_OKAY) {
toddouska 0:5045d2638c29 951 return res;
toddouska 0:5045d2638c29 952 }
toddouska 0:5045d2638c29 953
toddouska 0:5045d2638c29 954 /* init rest of tmps temps */
toddouska 0:5045d2638c29 955 if ((res = mp_init_multi(&C, &D, 0, 0, 0, 0)) != MP_OKAY) {
toddouska 0:5045d2638c29 956 return res;
toddouska 0:5045d2638c29 957 }
toddouska 0:5045d2638c29 958
toddouska 0:5045d2638c29 959 /* x = a, y = b */
toddouska 0:5045d2638c29 960 if ((res = mp_mod(a, b, &x)) != MP_OKAY) {
toddouska 0:5045d2638c29 961 goto LBL_ERR;
toddouska 0:5045d2638c29 962 }
toddouska 0:5045d2638c29 963 if ((res = mp_copy (b, &y)) != MP_OKAY) {
toddouska 0:5045d2638c29 964 goto LBL_ERR;
toddouska 0:5045d2638c29 965 }
toddouska 0:5045d2638c29 966
toddouska 0:5045d2638c29 967 /* 2. [modified] if x,y are both even then return an error! */
toddouska 0:5045d2638c29 968 if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) {
toddouska 0:5045d2638c29 969 res = MP_VAL;
toddouska 0:5045d2638c29 970 goto LBL_ERR;
toddouska 0:5045d2638c29 971 }
toddouska 0:5045d2638c29 972
toddouska 0:5045d2638c29 973 /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
toddouska 0:5045d2638c29 974 if ((res = mp_copy (&x, &u)) != MP_OKAY) {
toddouska 0:5045d2638c29 975 goto LBL_ERR;
toddouska 0:5045d2638c29 976 }
toddouska 0:5045d2638c29 977 if ((res = mp_copy (&y, &v)) != MP_OKAY) {
toddouska 0:5045d2638c29 978 goto LBL_ERR;
toddouska 0:5045d2638c29 979 }
toddouska 0:5045d2638c29 980 mp_set (&A, 1);
toddouska 0:5045d2638c29 981 mp_set (&D, 1);
toddouska 0:5045d2638c29 982
toddouska 0:5045d2638c29 983 top:
toddouska 0:5045d2638c29 984 /* 4. while u is even do */
toddouska 0:5045d2638c29 985 while (mp_iseven (&u) == 1) {
toddouska 0:5045d2638c29 986 /* 4.1 u = u/2 */
toddouska 0:5045d2638c29 987 if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
toddouska 0:5045d2638c29 988 goto LBL_ERR;
toddouska 0:5045d2638c29 989 }
toddouska 0:5045d2638c29 990 /* 4.2 if A or B is odd then */
toddouska 0:5045d2638c29 991 if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) {
toddouska 0:5045d2638c29 992 /* A = (A+y)/2, B = (B-x)/2 */
toddouska 0:5045d2638c29 993 if ((res = mp_add (&A, &y, &A)) != MP_OKAY) {
toddouska 0:5045d2638c29 994 goto LBL_ERR;
toddouska 0:5045d2638c29 995 }
toddouska 0:5045d2638c29 996 if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
toddouska 0:5045d2638c29 997 goto LBL_ERR;
toddouska 0:5045d2638c29 998 }
toddouska 0:5045d2638c29 999 }
toddouska 0:5045d2638c29 1000 /* A = A/2, B = B/2 */
toddouska 0:5045d2638c29 1001 if ((res = mp_div_2 (&A, &A)) != MP_OKAY) {
toddouska 0:5045d2638c29 1002 goto LBL_ERR;
toddouska 0:5045d2638c29 1003 }
toddouska 0:5045d2638c29 1004 if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
toddouska 0:5045d2638c29 1005 goto LBL_ERR;
toddouska 0:5045d2638c29 1006 }
toddouska 0:5045d2638c29 1007 }
toddouska 0:5045d2638c29 1008
toddouska 0:5045d2638c29 1009 /* 5. while v is even do */
toddouska 0:5045d2638c29 1010 while (mp_iseven (&v) == 1) {
toddouska 0:5045d2638c29 1011 /* 5.1 v = v/2 */
toddouska 0:5045d2638c29 1012 if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
toddouska 0:5045d2638c29 1013 goto LBL_ERR;
toddouska 0:5045d2638c29 1014 }
toddouska 0:5045d2638c29 1015 /* 5.2 if C or D is odd then */
toddouska 0:5045d2638c29 1016 if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) {
toddouska 0:5045d2638c29 1017 /* C = (C+y)/2, D = (D-x)/2 */
toddouska 0:5045d2638c29 1018 if ((res = mp_add (&C, &y, &C)) != MP_OKAY) {
toddouska 0:5045d2638c29 1019 goto LBL_ERR;
toddouska 0:5045d2638c29 1020 }
toddouska 0:5045d2638c29 1021 if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
toddouska 0:5045d2638c29 1022 goto LBL_ERR;
toddouska 0:5045d2638c29 1023 }
toddouska 0:5045d2638c29 1024 }
toddouska 0:5045d2638c29 1025 /* C = C/2, D = D/2 */
toddouska 0:5045d2638c29 1026 if ((res = mp_div_2 (&C, &C)) != MP_OKAY) {
toddouska 0:5045d2638c29 1027 goto LBL_ERR;
toddouska 0:5045d2638c29 1028 }
toddouska 0:5045d2638c29 1029 if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
toddouska 0:5045d2638c29 1030 goto LBL_ERR;
toddouska 0:5045d2638c29 1031 }
toddouska 0:5045d2638c29 1032 }
toddouska 0:5045d2638c29 1033
toddouska 0:5045d2638c29 1034 /* 6. if u >= v then */
toddouska 0:5045d2638c29 1035 if (mp_cmp (&u, &v) != MP_LT) {
toddouska 0:5045d2638c29 1036 /* u = u - v, A = A - C, B = B - D */
toddouska 0:5045d2638c29 1037 if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
toddouska 0:5045d2638c29 1038 goto LBL_ERR;
toddouska 0:5045d2638c29 1039 }
toddouska 0:5045d2638c29 1040
toddouska 0:5045d2638c29 1041 if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) {
toddouska 0:5045d2638c29 1042 goto LBL_ERR;
toddouska 0:5045d2638c29 1043 }
toddouska 0:5045d2638c29 1044
toddouska 0:5045d2638c29 1045 if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
toddouska 0:5045d2638c29 1046 goto LBL_ERR;
toddouska 0:5045d2638c29 1047 }
toddouska 0:5045d2638c29 1048 } else {
toddouska 0:5045d2638c29 1049 /* v - v - u, C = C - A, D = D - B */
toddouska 0:5045d2638c29 1050 if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
toddouska 0:5045d2638c29 1051 goto LBL_ERR;
toddouska 0:5045d2638c29 1052 }
toddouska 0:5045d2638c29 1053
toddouska 0:5045d2638c29 1054 if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) {
toddouska 0:5045d2638c29 1055 goto LBL_ERR;
toddouska 0:5045d2638c29 1056 }
toddouska 0:5045d2638c29 1057
toddouska 0:5045d2638c29 1058 if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
toddouska 0:5045d2638c29 1059 goto LBL_ERR;
toddouska 0:5045d2638c29 1060 }
toddouska 0:5045d2638c29 1061 }
toddouska 0:5045d2638c29 1062
toddouska 0:5045d2638c29 1063 /* if not zero goto step 4 */
toddouska 0:5045d2638c29 1064 if (mp_iszero (&u) == 0)
toddouska 0:5045d2638c29 1065 goto top;
toddouska 0:5045d2638c29 1066
toddouska 0:5045d2638c29 1067 /* now a = C, b = D, gcd == g*v */
toddouska 0:5045d2638c29 1068
toddouska 0:5045d2638c29 1069 /* if v != 1 then there is no inverse */
toddouska 0:5045d2638c29 1070 if (mp_cmp_d (&v, 1) != MP_EQ) {
toddouska 0:5045d2638c29 1071 res = MP_VAL;
toddouska 0:5045d2638c29 1072 goto LBL_ERR;
toddouska 0:5045d2638c29 1073 }
toddouska 0:5045d2638c29 1074
toddouska 0:5045d2638c29 1075 /* if its too low */
toddouska 0:5045d2638c29 1076 while (mp_cmp_d(&C, 0) == MP_LT) {
toddouska 0:5045d2638c29 1077 if ((res = mp_add(&C, b, &C)) != MP_OKAY) {
toddouska 0:5045d2638c29 1078 goto LBL_ERR;
toddouska 0:5045d2638c29 1079 }
toddouska 0:5045d2638c29 1080 }
toddouska 0:5045d2638c29 1081
toddouska 0:5045d2638c29 1082 /* too big */
toddouska 0:5045d2638c29 1083 while (mp_cmp_mag(&C, b) != MP_LT) {
toddouska 0:5045d2638c29 1084 if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
toddouska 0:5045d2638c29 1085 goto LBL_ERR;
toddouska 0:5045d2638c29 1086 }
toddouska 0:5045d2638c29 1087 }
toddouska 0:5045d2638c29 1088
toddouska 0:5045d2638c29 1089 /* C is now the inverse */
toddouska 0:5045d2638c29 1090 mp_exch (&C, c);
toddouska 0:5045d2638c29 1091 res = MP_OKAY;
toddouska 0:5045d2638c29 1092 LBL_ERR:mp_clear(&x);
toddouska 0:5045d2638c29 1093 mp_clear(&y);
toddouska 0:5045d2638c29 1094 mp_clear(&u);
toddouska 0:5045d2638c29 1095 mp_clear(&v);
toddouska 0:5045d2638c29 1096 mp_clear(&A);
toddouska 0:5045d2638c29 1097 mp_clear(&B);
toddouska 0:5045d2638c29 1098 mp_clear(&C);
toddouska 0:5045d2638c29 1099 mp_clear(&D);
toddouska 0:5045d2638c29 1100 return res;
toddouska 0:5045d2638c29 1101 }
toddouska 0:5045d2638c29 1102
toddouska 0:5045d2638c29 1103
toddouska 0:5045d2638c29 1104 /* compare maginitude of two ints (unsigned) */
toddouska 0:5045d2638c29 1105 int mp_cmp_mag (mp_int * a, mp_int * b)
toddouska 0:5045d2638c29 1106 {
toddouska 0:5045d2638c29 1107 int n;
toddouska 0:5045d2638c29 1108 mp_digit *tmpa, *tmpb;
toddouska 0:5045d2638c29 1109
toddouska 0:5045d2638c29 1110 /* compare based on # of non-zero digits */
toddouska 0:5045d2638c29 1111 if (a->used > b->used) {
toddouska 0:5045d2638c29 1112 return MP_GT;
toddouska 0:5045d2638c29 1113 }
toddouska 0:5045d2638c29 1114
toddouska 0:5045d2638c29 1115 if (a->used < b->used) {
toddouska 0:5045d2638c29 1116 return MP_LT;
toddouska 0:5045d2638c29 1117 }
toddouska 0:5045d2638c29 1118
toddouska 0:5045d2638c29 1119 /* alias for a */
toddouska 0:5045d2638c29 1120 tmpa = a->dp + (a->used - 1);
toddouska 0:5045d2638c29 1121
toddouska 0:5045d2638c29 1122 /* alias for b */
toddouska 0:5045d2638c29 1123 tmpb = b->dp + (a->used - 1);
toddouska 0:5045d2638c29 1124
toddouska 0:5045d2638c29 1125 /* compare based on digits */
toddouska 0:5045d2638c29 1126 for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
toddouska 0:5045d2638c29 1127 if (*tmpa > *tmpb) {
toddouska 0:5045d2638c29 1128 return MP_GT;
toddouska 0:5045d2638c29 1129 }
toddouska 0:5045d2638c29 1130
toddouska 0:5045d2638c29 1131 if (*tmpa < *tmpb) {
toddouska 0:5045d2638c29 1132 return MP_LT;
toddouska 0:5045d2638c29 1133 }
toddouska 0:5045d2638c29 1134 }
toddouska 0:5045d2638c29 1135 return MP_EQ;
toddouska 0:5045d2638c29 1136 }
toddouska 0:5045d2638c29 1137
toddouska 0:5045d2638c29 1138
toddouska 0:5045d2638c29 1139 /* compare two ints (signed)*/
toddouska 0:5045d2638c29 1140 int
toddouska 0:5045d2638c29 1141 mp_cmp (mp_int * a, mp_int * b)
toddouska 0:5045d2638c29 1142 {
toddouska 0:5045d2638c29 1143 /* compare based on sign */
toddouska 0:5045d2638c29 1144 if (a->sign != b->sign) {
toddouska 0:5045d2638c29 1145 if (a->sign == MP_NEG) {
toddouska 0:5045d2638c29 1146 return MP_LT;
toddouska 0:5045d2638c29 1147 } else {
toddouska 0:5045d2638c29 1148 return MP_GT;
toddouska 0:5045d2638c29 1149 }
toddouska 0:5045d2638c29 1150 }
toddouska 0:5045d2638c29 1151
toddouska 0:5045d2638c29 1152 /* compare digits */
toddouska 0:5045d2638c29 1153 if (a->sign == MP_NEG) {
toddouska 0:5045d2638c29 1154 /* if negative compare opposite direction */
toddouska 0:5045d2638c29 1155 return mp_cmp_mag(b, a);
toddouska 0:5045d2638c29 1156 } else {
toddouska 0:5045d2638c29 1157 return mp_cmp_mag(a, b);
toddouska 0:5045d2638c29 1158 }
toddouska 0:5045d2638c29 1159 }
toddouska 0:5045d2638c29 1160
toddouska 0:5045d2638c29 1161
toddouska 0:5045d2638c29 1162 /* compare a digit */
toddouska 0:5045d2638c29 1163 int mp_cmp_d(mp_int * a, mp_digit b)
toddouska 0:5045d2638c29 1164 {
toddouska 0:5045d2638c29 1165 /* compare based on sign */
toddouska 0:5045d2638c29 1166 if (a->sign == MP_NEG) {
toddouska 0:5045d2638c29 1167 return MP_LT;
toddouska 0:5045d2638c29 1168 }
toddouska 0:5045d2638c29 1169
toddouska 0:5045d2638c29 1170 /* compare based on magnitude */
toddouska 0:5045d2638c29 1171 if (a->used > 1) {
toddouska 0:5045d2638c29 1172 return MP_GT;
toddouska 0:5045d2638c29 1173 }
toddouska 0:5045d2638c29 1174
toddouska 0:5045d2638c29 1175 /* compare the only digit of a to b */
toddouska 0:5045d2638c29 1176 if (a->dp[0] > b) {
toddouska 0:5045d2638c29 1177 return MP_GT;
toddouska 0:5045d2638c29 1178 } else if (a->dp[0] < b) {
toddouska 0:5045d2638c29 1179 return MP_LT;
toddouska 0:5045d2638c29 1180 } else {
toddouska 0:5045d2638c29 1181 return MP_EQ;
toddouska 0:5045d2638c29 1182 }
toddouska 0:5045d2638c29 1183 }
toddouska 0:5045d2638c29 1184
toddouska 0:5045d2638c29 1185
toddouska 0:5045d2638c29 1186 /* set to a digit */
toddouska 0:5045d2638c29 1187 void mp_set (mp_int * a, mp_digit b)
toddouska 0:5045d2638c29 1188 {
toddouska 0:5045d2638c29 1189 mp_zero (a);
toddouska 0:5045d2638c29 1190 a->dp[0] = b & MP_MASK;
toddouska 0:5045d2638c29 1191 a->used = (a->dp[0] != 0) ? 1 : 0;
toddouska 0:5045d2638c29 1192 }
toddouska 0:5045d2638c29 1193
toddouska 0:5045d2638c29 1194
toddouska 0:5045d2638c29 1195 /* c = a mod b, 0 <= c < b */
toddouska 0:5045d2638c29 1196 int
toddouska 0:5045d2638c29 1197 mp_mod (mp_int * a, mp_int * b, mp_int * c)
toddouska 0:5045d2638c29 1198 {
toddouska 0:5045d2638c29 1199 mp_int t;
toddouska 0:5045d2638c29 1200 int res;
toddouska 0:5045d2638c29 1201
toddouska 0:5045d2638c29 1202 if ((res = mp_init (&t)) != MP_OKAY) {
toddouska 0:5045d2638c29 1203 return res;
toddouska 0:5045d2638c29 1204 }
toddouska 0:5045d2638c29 1205
toddouska 0:5045d2638c29 1206 if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) {
toddouska 0:5045d2638c29 1207 mp_clear (&t);
toddouska 0:5045d2638c29 1208 return res;
toddouska 0:5045d2638c29 1209 }
toddouska 0:5045d2638c29 1210
toddouska 0:5045d2638c29 1211 if (t.sign != b->sign) {
toddouska 0:5045d2638c29 1212 res = mp_add (b, &t, c);
toddouska 0:5045d2638c29 1213 } else {
toddouska 0:5045d2638c29 1214 res = MP_OKAY;
toddouska 0:5045d2638c29 1215 mp_exch (&t, c);
toddouska 0:5045d2638c29 1216 }
toddouska 0:5045d2638c29 1217
toddouska 0:5045d2638c29 1218 mp_clear (&t);
toddouska 0:5045d2638c29 1219 return res;
toddouska 0:5045d2638c29 1220 }
toddouska 0:5045d2638c29 1221
toddouska 0:5045d2638c29 1222
toddouska 0:5045d2638c29 1223 /* slower bit-bang division... also smaller */
toddouska 0:5045d2638c29 1224 int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
toddouska 0:5045d2638c29 1225 {
toddouska 0:5045d2638c29 1226 mp_int ta, tb, tq, q;
toddouska 0:5045d2638c29 1227 int res, n, n2;
toddouska 0:5045d2638c29 1228
toddouska 0:5045d2638c29 1229 /* is divisor zero ? */
toddouska 0:5045d2638c29 1230 if (mp_iszero (b) == 1) {
toddouska 0:5045d2638c29 1231 return MP_VAL;
toddouska 0:5045d2638c29 1232 }
toddouska 0:5045d2638c29 1233
toddouska 0:5045d2638c29 1234 /* if a < b then q=0, r = a */
toddouska 0:5045d2638c29 1235 if (mp_cmp_mag (a, b) == MP_LT) {
toddouska 0:5045d2638c29 1236 if (d != NULL) {
toddouska 0:5045d2638c29 1237 res = mp_copy (a, d);
toddouska 0:5045d2638c29 1238 } else {
toddouska 0:5045d2638c29 1239 res = MP_OKAY;
toddouska 0:5045d2638c29 1240 }
toddouska 0:5045d2638c29 1241 if (c != NULL) {
toddouska 0:5045d2638c29 1242 mp_zero (c);
toddouska 0:5045d2638c29 1243 }
toddouska 0:5045d2638c29 1244 return res;
toddouska 0:5045d2638c29 1245 }
toddouska 0:5045d2638c29 1246
toddouska 0:5045d2638c29 1247 /* init our temps */
toddouska 0:5045d2638c29 1248 if ((res = mp_init_multi(&ta, &tb, &tq, &q, 0, 0) != MP_OKAY)) {
toddouska 0:5045d2638c29 1249 return res;
toddouska 0:5045d2638c29 1250 }
toddouska 0:5045d2638c29 1251
toddouska 0:5045d2638c29 1252
toddouska 0:5045d2638c29 1253 mp_set(&tq, 1);
toddouska 0:5045d2638c29 1254 n = mp_count_bits(a) - mp_count_bits(b);
toddouska 0:5045d2638c29 1255 if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
toddouska 0:5045d2638c29 1256 ((res = mp_abs(b, &tb)) != MP_OKAY) ||
toddouska 0:5045d2638c29 1257 ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
toddouska 0:5045d2638c29 1258 ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
toddouska 0:5045d2638c29 1259 goto LBL_ERR;
toddouska 0:5045d2638c29 1260 }
toddouska 0:5045d2638c29 1261
toddouska 0:5045d2638c29 1262 while (n-- >= 0) {
toddouska 0:5045d2638c29 1263 if (mp_cmp(&tb, &ta) != MP_GT) {
toddouska 0:5045d2638c29 1264 if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) ||
toddouska 0:5045d2638c29 1265 ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) {
toddouska 0:5045d2638c29 1266 goto LBL_ERR;
toddouska 0:5045d2638c29 1267 }
toddouska 0:5045d2638c29 1268 }
toddouska 0:5045d2638c29 1269 if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) ||
toddouska 0:5045d2638c29 1270 ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) {
toddouska 0:5045d2638c29 1271 goto LBL_ERR;
toddouska 0:5045d2638c29 1272 }
toddouska 0:5045d2638c29 1273 }
toddouska 0:5045d2638c29 1274
toddouska 0:5045d2638c29 1275 /* now q == quotient and ta == remainder */
toddouska 0:5045d2638c29 1276 n = a->sign;
toddouska 0:5045d2638c29 1277 n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG);
toddouska 0:5045d2638c29 1278 if (c != NULL) {
toddouska 0:5045d2638c29 1279 mp_exch(c, &q);
toddouska 0:5045d2638c29 1280 c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2;
toddouska 0:5045d2638c29 1281 }
toddouska 0:5045d2638c29 1282 if (d != NULL) {
toddouska 0:5045d2638c29 1283 mp_exch(d, &ta);
toddouska 0:5045d2638c29 1284 d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n;
toddouska 0:5045d2638c29 1285 }
toddouska 0:5045d2638c29 1286 LBL_ERR:
toddouska 0:5045d2638c29 1287 mp_clear(&ta);
toddouska 0:5045d2638c29 1288 mp_clear(&tb);
toddouska 0:5045d2638c29 1289 mp_clear(&tq);
toddouska 0:5045d2638c29 1290 mp_clear(&q);
toddouska 0:5045d2638c29 1291 return res;
toddouska 0:5045d2638c29 1292 }
toddouska 0:5045d2638c29 1293
toddouska 0:5045d2638c29 1294
toddouska 0:5045d2638c29 1295 /* b = a/2 */
toddouska 0:5045d2638c29 1296 int mp_div_2(mp_int * a, mp_int * b)
toddouska 0:5045d2638c29 1297 {
toddouska 0:5045d2638c29 1298 int x, res, oldused;
toddouska 0:5045d2638c29 1299
toddouska 0:5045d2638c29 1300 /* copy */
toddouska 0:5045d2638c29 1301 if (b->alloc < a->used) {
toddouska 0:5045d2638c29 1302 if ((res = mp_grow (b, a->used)) != MP_OKAY) {
toddouska 0:5045d2638c29 1303 return res;
toddouska 0:5045d2638c29 1304 }
toddouska 0:5045d2638c29 1305 }
toddouska 0:5045d2638c29 1306
toddouska 0:5045d2638c29 1307 oldused = b->used;
toddouska 0:5045d2638c29 1308 b->used = a->used;
toddouska 0:5045d2638c29 1309 {
toddouska 0:5045d2638c29 1310 register mp_digit r, rr, *tmpa, *tmpb;
toddouska 0:5045d2638c29 1311
toddouska 0:5045d2638c29 1312 /* source alias */
toddouska 0:5045d2638c29 1313 tmpa = a->dp + b->used - 1;
toddouska 0:5045d2638c29 1314
toddouska 0:5045d2638c29 1315 /* dest alias */
toddouska 0:5045d2638c29 1316 tmpb = b->dp + b->used - 1;
toddouska 0:5045d2638c29 1317
toddouska 0:5045d2638c29 1318 /* carry */
toddouska 0:5045d2638c29 1319 r = 0;
toddouska 0:5045d2638c29 1320 for (x = b->used - 1; x >= 0; x--) {
toddouska 0:5045d2638c29 1321 /* get the carry for the next iteration */
toddouska 0:5045d2638c29 1322 rr = *tmpa & 1;
toddouska 0:5045d2638c29 1323
toddouska 0:5045d2638c29 1324 /* shift the current digit, add in carry and store */
toddouska 0:5045d2638c29 1325 *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
toddouska 0:5045d2638c29 1326
toddouska 0:5045d2638c29 1327 /* forward carry to next iteration */
toddouska 0:5045d2638c29 1328 r = rr;
toddouska 0:5045d2638c29 1329 }
toddouska 0:5045d2638c29 1330
toddouska 0:5045d2638c29 1331 /* zero excess digits */
toddouska 0:5045d2638c29 1332 tmpb = b->dp + b->used;
toddouska 0:5045d2638c29 1333 for (x = b->used; x < oldused; x++) {
toddouska 0:5045d2638c29 1334 *tmpb++ = 0;
toddouska 0:5045d2638c29 1335 }
toddouska 0:5045d2638c29 1336 }
toddouska 0:5045d2638c29 1337 b->sign = a->sign;
toddouska 0:5045d2638c29 1338 mp_clamp (b);
toddouska 0:5045d2638c29 1339 return MP_OKAY;
toddouska 0:5045d2638c29 1340 }
toddouska 0:5045d2638c29 1341
toddouska 0:5045d2638c29 1342
toddouska 0:5045d2638c29 1343 /* high level addition (handles signs) */
toddouska 0:5045d2638c29 1344 int mp_add (mp_int * a, mp_int * b, mp_int * c)
toddouska 0:5045d2638c29 1345 {
toddouska 0:5045d2638c29 1346 int sa, sb, res;
toddouska 0:5045d2638c29 1347
toddouska 0:5045d2638c29 1348 /* get sign of both inputs */
toddouska 0:5045d2638c29 1349 sa = a->sign;
toddouska 0:5045d2638c29 1350 sb = b->sign;
toddouska 0:5045d2638c29 1351
toddouska 0:5045d2638c29 1352 /* handle two cases, not four */
toddouska 0:5045d2638c29 1353 if (sa == sb) {
toddouska 0:5045d2638c29 1354 /* both positive or both negative */
toddouska 0:5045d2638c29 1355 /* add their magnitudes, copy the sign */
toddouska 0:5045d2638c29 1356 c->sign = sa;
toddouska 0:5045d2638c29 1357 res = s_mp_add (a, b, c);
toddouska 0:5045d2638c29 1358 } else {
toddouska 0:5045d2638c29 1359 /* one positive, the other negative */
toddouska 0:5045d2638c29 1360 /* subtract the one with the greater magnitude from */
toddouska 0:5045d2638c29 1361 /* the one of the lesser magnitude. The result gets */
toddouska 0:5045d2638c29 1362 /* the sign of the one with the greater magnitude. */
toddouska 0:5045d2638c29 1363 if (mp_cmp_mag (a, b) == MP_LT) {
toddouska 0:5045d2638c29 1364 c->sign = sb;
toddouska 0:5045d2638c29 1365 res = s_mp_sub (b, a, c);
toddouska 0:5045d2638c29 1366 } else {
toddouska 0:5045d2638c29 1367 c->sign = sa;
toddouska 0:5045d2638c29 1368 res = s_mp_sub (a, b, c);
toddouska 0:5045d2638c29 1369 }
toddouska 0:5045d2638c29 1370 }
toddouska 0:5045d2638c29 1371 return res;
toddouska 0:5045d2638c29 1372 }
toddouska 0:5045d2638c29 1373
toddouska 0:5045d2638c29 1374
toddouska 0:5045d2638c29 1375 /* low level addition, based on HAC pp.594, Algorithm 14.7 */
toddouska 0:5045d2638c29 1376 int
toddouska 0:5045d2638c29 1377 s_mp_add (mp_int * a, mp_int * b, mp_int * c)
toddouska 0:5045d2638c29 1378 {
toddouska 0:5045d2638c29 1379 mp_int *x;
toddouska 0:5045d2638c29 1380 int olduse, res, min, max;
toddouska 0:5045d2638c29 1381
toddouska 0:5045d2638c29 1382 /* find sizes, we let |a| <= |b| which means we have to sort
toddouska 0:5045d2638c29 1383 * them. "x" will point to the input with the most digits
toddouska 0:5045d2638c29 1384 */
toddouska 0:5045d2638c29 1385 if (a->used > b->used) {
toddouska 0:5045d2638c29 1386 min = b->used;
toddouska 0:5045d2638c29 1387 max = a->used;
toddouska 0:5045d2638c29 1388 x = a;
toddouska 0:5045d2638c29 1389 } else {
toddouska 0:5045d2638c29 1390 min = a->used;
toddouska 0:5045d2638c29 1391 max = b->used;
toddouska 0:5045d2638c29 1392 x = b;
toddouska 0:5045d2638c29 1393 }
toddouska 0:5045d2638c29 1394
toddouska 0:5045d2638c29 1395 /* init result */
toddouska 0:5045d2638c29 1396 if (c->alloc < max + 1) {
toddouska 0:5045d2638c29 1397 if ((res = mp_grow (c, max + 1)) != MP_OKAY) {
toddouska 0:5045d2638c29 1398 return res;
toddouska 0:5045d2638c29 1399 }
toddouska 0:5045d2638c29 1400 }
toddouska 0:5045d2638c29 1401
toddouska 0:5045d2638c29 1402 /* get old used digit count and set new one */
toddouska 0:5045d2638c29 1403 olduse = c->used;
toddouska 0:5045d2638c29 1404 c->used = max + 1;
toddouska 0:5045d2638c29 1405
toddouska 0:5045d2638c29 1406 {
toddouska 0:5045d2638c29 1407 register mp_digit u, *tmpa, *tmpb, *tmpc;
toddouska 0:5045d2638c29 1408 register int i;
toddouska 0:5045d2638c29 1409
toddouska 0:5045d2638c29 1410 /* alias for digit pointers */
toddouska 0:5045d2638c29 1411
toddouska 0:5045d2638c29 1412 /* first input */
toddouska 0:5045d2638c29 1413 tmpa = a->dp;
toddouska 0:5045d2638c29 1414
toddouska 0:5045d2638c29 1415 /* second input */
toddouska 0:5045d2638c29 1416 tmpb = b->dp;
toddouska 0:5045d2638c29 1417
toddouska 0:5045d2638c29 1418 /* destination */
toddouska 0:5045d2638c29 1419 tmpc = c->dp;
toddouska 0:5045d2638c29 1420
toddouska 0:5045d2638c29 1421 /* zero the carry */
toddouska 0:5045d2638c29 1422 u = 0;
toddouska 0:5045d2638c29 1423 for (i = 0; i < min; i++) {
toddouska 0:5045d2638c29 1424 /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */
toddouska 0:5045d2638c29 1425 *tmpc = *tmpa++ + *tmpb++ + u;
toddouska 0:5045d2638c29 1426
toddouska 0:5045d2638c29 1427 /* U = carry bit of T[i] */
toddouska 0:5045d2638c29 1428 u = *tmpc >> ((mp_digit)DIGIT_BIT);
toddouska 0:5045d2638c29 1429
toddouska 0:5045d2638c29 1430 /* take away carry bit from T[i] */
toddouska 0:5045d2638c29 1431 *tmpc++ &= MP_MASK;
toddouska 0:5045d2638c29 1432 }
toddouska 0:5045d2638c29 1433
toddouska 0:5045d2638c29 1434 /* now copy higher words if any, that is in A+B
toddouska 0:5045d2638c29 1435 * if A or B has more digits add those in
toddouska 0:5045d2638c29 1436 */
toddouska 0:5045d2638c29 1437 if (min != max) {
toddouska 0:5045d2638c29 1438 for (; i < max; i++) {
toddouska 0:5045d2638c29 1439 /* T[i] = X[i] + U */
toddouska 0:5045d2638c29 1440 *tmpc = x->dp[i] + u;
toddouska 0:5045d2638c29 1441
toddouska 0:5045d2638c29 1442 /* U = carry bit of T[i] */
toddouska 0:5045d2638c29 1443 u = *tmpc >> ((mp_digit)DIGIT_BIT);
toddouska 0:5045d2638c29 1444
toddouska 0:5045d2638c29 1445 /* take away carry bit from T[i] */
toddouska 0:5045d2638c29 1446 *tmpc++ &= MP_MASK;
toddouska 0:5045d2638c29 1447 }
toddouska 0:5045d2638c29 1448 }
toddouska 0:5045d2638c29 1449
toddouska 0:5045d2638c29 1450 /* add carry */
toddouska 0:5045d2638c29 1451 *tmpc++ = u;
toddouska 0:5045d2638c29 1452
toddouska 0:5045d2638c29 1453 /* clear digits above oldused */
toddouska 0:5045d2638c29 1454 for (i = c->used; i < olduse; i++) {
toddouska 0:5045d2638c29 1455 *tmpc++ = 0;
toddouska 0:5045d2638c29 1456 }
toddouska 0:5045d2638c29 1457 }
toddouska 0:5045d2638c29 1458
toddouska 0:5045d2638c29 1459 mp_clamp (c);
toddouska 0:5045d2638c29 1460 return MP_OKAY;
toddouska 0:5045d2638c29 1461 }
toddouska 0:5045d2638c29 1462
toddouska 0:5045d2638c29 1463
toddouska 0:5045d2638c29 1464 /* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
toddouska 0:5045d2638c29 1465 int
toddouska 0:5045d2638c29 1466 s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
toddouska 0:5045d2638c29 1467 {
toddouska 0:5045d2638c29 1468 int olduse, res, min, max;
toddouska 0:5045d2638c29 1469
toddouska 0:5045d2638c29 1470 /* find sizes */
toddouska 0:5045d2638c29 1471 min = b->used;
toddouska 0:5045d2638c29 1472 max = a->used;
toddouska 0:5045d2638c29 1473
toddouska 0:5045d2638c29 1474 /* init result */
toddouska 0:5045d2638c29 1475 if (c->alloc < max) {
toddouska 0:5045d2638c29 1476 if ((res = mp_grow (c, max)) != MP_OKAY) {
toddouska 0:5045d2638c29 1477 return res;
toddouska 0:5045d2638c29 1478 }
toddouska 0:5045d2638c29 1479 }
toddouska 0:5045d2638c29 1480 olduse = c->used;
toddouska 0:5045d2638c29 1481 c->used = max;
toddouska 0:5045d2638c29 1482
toddouska 0:5045d2638c29 1483 {
toddouska 0:5045d2638c29 1484 register mp_digit u, *tmpa, *tmpb, *tmpc;
toddouska 0:5045d2638c29 1485 register int i;
toddouska 0:5045d2638c29 1486
toddouska 0:5045d2638c29 1487 /* alias for digit pointers */
toddouska 0:5045d2638c29 1488 tmpa = a->dp;
toddouska 0:5045d2638c29 1489 tmpb = b->dp;
toddouska 0:5045d2638c29 1490 tmpc = c->dp;
toddouska 0:5045d2638c29 1491
toddouska 0:5045d2638c29 1492 /* set carry to zero */
toddouska 0:5045d2638c29 1493 u = 0;
toddouska 0:5045d2638c29 1494 for (i = 0; i < min; i++) {
toddouska 0:5045d2638c29 1495 /* T[i] = A[i] - B[i] - U */
toddouska 0:5045d2638c29 1496 *tmpc = *tmpa++ - *tmpb++ - u;
toddouska 0:5045d2638c29 1497
toddouska 0:5045d2638c29 1498 /* U = carry bit of T[i]
toddouska 0:5045d2638c29 1499 * Note this saves performing an AND operation since
toddouska 0:5045d2638c29 1500 * if a carry does occur it will propagate all the way to the
toddouska 0:5045d2638c29 1501 * MSB. As a result a single shift is enough to get the carry
toddouska 0:5045d2638c29 1502 */
toddouska 0:5045d2638c29 1503 u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
toddouska 0:5045d2638c29 1504
toddouska 0:5045d2638c29 1505 /* Clear carry from T[i] */
toddouska 0:5045d2638c29 1506 *tmpc++ &= MP_MASK;
toddouska 0:5045d2638c29 1507 }
toddouska 0:5045d2638c29 1508
toddouska 0:5045d2638c29 1509 /* now copy higher words if any, e.g. if A has more digits than B */
toddouska 0:5045d2638c29 1510 for (; i < max; i++) {
toddouska 0:5045d2638c29 1511 /* T[i] = A[i] - U */
toddouska 0:5045d2638c29 1512 *tmpc = *tmpa++ - u;
toddouska 0:5045d2638c29 1513
toddouska 0:5045d2638c29 1514 /* U = carry bit of T[i] */
toddouska 0:5045d2638c29 1515 u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
toddouska 0:5045d2638c29 1516
toddouska 0:5045d2638c29 1517 /* Clear carry from T[i] */
toddouska 0:5045d2638c29 1518 *tmpc++ &= MP_MASK;
toddouska 0:5045d2638c29 1519 }
toddouska 0:5045d2638c29 1520
toddouska 0:5045d2638c29 1521 /* clear digits above used (since we may not have grown result above) */
toddouska 0:5045d2638c29 1522 for (i = c->used; i < olduse; i++) {
toddouska 0:5045d2638c29 1523 *tmpc++ = 0;
toddouska 0:5045d2638c29 1524 }
toddouska 0:5045d2638c29 1525 }
toddouska 0:5045d2638c29 1526
toddouska 0:5045d2638c29 1527 mp_clamp (c);
toddouska 0:5045d2638c29 1528 return MP_OKAY;
toddouska 0:5045d2638c29 1529 }
toddouska 0:5045d2638c29 1530
toddouska 0:5045d2638c29 1531
toddouska 0:5045d2638c29 1532 /* high level subtraction (handles signs) */
toddouska 0:5045d2638c29 1533 int
toddouska 0:5045d2638c29 1534 mp_sub (mp_int * a, mp_int * b, mp_int * c)
toddouska 0:5045d2638c29 1535 {
toddouska 0:5045d2638c29 1536 int sa, sb, res;
toddouska 0:5045d2638c29 1537
toddouska 0:5045d2638c29 1538 sa = a->sign;
toddouska 0:5045d2638c29 1539 sb = b->sign;
toddouska 0:5045d2638c29 1540
toddouska 0:5045d2638c29 1541 if (sa != sb) {
toddouska 0:5045d2638c29 1542 /* subtract a negative from a positive, OR */
toddouska 0:5045d2638c29 1543 /* subtract a positive from a negative. */
toddouska 0:5045d2638c29 1544 /* In either case, ADD their magnitudes, */
toddouska 0:5045d2638c29 1545 /* and use the sign of the first number. */
toddouska 0:5045d2638c29 1546 c->sign = sa;
toddouska 0:5045d2638c29 1547 res = s_mp_add (a, b, c);
toddouska 0:5045d2638c29 1548 } else {
toddouska 0:5045d2638c29 1549 /* subtract a positive from a positive, OR */
toddouska 0:5045d2638c29 1550 /* subtract a negative from a negative. */
toddouska 0:5045d2638c29 1551 /* First, take the difference between their */
toddouska 0:5045d2638c29 1552 /* magnitudes, then... */
toddouska 0:5045d2638c29 1553 if (mp_cmp_mag (a, b) != MP_LT) {
toddouska 0:5045d2638c29 1554 /* Copy the sign from the first */
toddouska 0:5045d2638c29 1555 c->sign = sa;
toddouska 0:5045d2638c29 1556 /* The first has a larger or equal magnitude */
toddouska 0:5045d2638c29 1557 res = s_mp_sub (a, b, c);
toddouska 0:5045d2638c29 1558 } else {
toddouska 0:5045d2638c29 1559 /* The result has the *opposite* sign from */
toddouska 0:5045d2638c29 1560 /* the first number. */
toddouska 0:5045d2638c29 1561 c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
toddouska 0:5045d2638c29 1562 /* The second has a larger magnitude */
toddouska 0:5045d2638c29 1563 res = s_mp_sub (b, a, c);
toddouska 0:5045d2638c29 1564 }
toddouska 0:5045d2638c29 1565 }
toddouska 0:5045d2638c29 1566 return res;
toddouska 0:5045d2638c29 1567 }
toddouska 0:5045d2638c29 1568
toddouska 0:5045d2638c29 1569
toddouska 0:5045d2638c29 1570 /* determines if reduce_2k_l can be used */
toddouska 0:5045d2638c29 1571 int mp_reduce_is_2k_l(mp_int *a)
toddouska 0:5045d2638c29 1572 {
toddouska 0:5045d2638c29 1573 int ix, iy;
toddouska 0:5045d2638c29 1574
toddouska 0:5045d2638c29 1575 if (a->used == 0) {
toddouska 0:5045d2638c29 1576 return MP_NO;
toddouska 0:5045d2638c29 1577 } else if (a->used == 1) {
toddouska 0:5045d2638c29 1578 return MP_YES;
toddouska 0:5045d2638c29 1579 } else if (a->used > 1) {
toddouska 0:5045d2638c29 1580 /* if more than half of the digits are -1 we're sold */
toddouska 0:5045d2638c29 1581 for (iy = ix = 0; ix < a->used; ix++) {
toddouska 0:5045d2638c29 1582 if (a->dp[ix] == MP_MASK) {
toddouska 0:5045d2638c29 1583 ++iy;
toddouska 0:5045d2638c29 1584 }
toddouska 0:5045d2638c29 1585 }
toddouska 0:5045d2638c29 1586 return (iy >= (a->used/2)) ? MP_YES : MP_NO;
toddouska 0:5045d2638c29 1587
toddouska 0:5045d2638c29 1588 }
toddouska 0:5045d2638c29 1589 return MP_NO;
toddouska 0:5045d2638c29 1590 }
toddouska 0:5045d2638c29 1591
toddouska 0:5045d2638c29 1592
toddouska 0:5045d2638c29 1593 /* determines if mp_reduce_2k can be used */
toddouska 0:5045d2638c29 1594 int mp_reduce_is_2k(mp_int *a)
toddouska 0:5045d2638c29 1595 {
toddouska 0:5045d2638c29 1596 int ix, iy, iw;
toddouska 0:5045d2638c29 1597 mp_digit iz;
toddouska 0:5045d2638c29 1598
toddouska 0:5045d2638c29 1599 if (a->used == 0) {
toddouska 0:5045d2638c29 1600 return MP_NO;
toddouska 0:5045d2638c29 1601 } else if (a->used == 1) {
toddouska 0:5045d2638c29 1602 return MP_YES;
toddouska 0:5045d2638c29 1603 } else if (a->used > 1) {
toddouska 0:5045d2638c29 1604 iy = mp_count_bits(a);
toddouska 0:5045d2638c29 1605 iz = 1;
toddouska 0:5045d2638c29 1606 iw = 1;
toddouska 0:5045d2638c29 1607
toddouska 0:5045d2638c29 1608 /* Test every bit from the second digit up, must be 1 */
toddouska 0:5045d2638c29 1609 for (ix = DIGIT_BIT; ix < iy; ix++) {
toddouska 0:5045d2638c29 1610 if ((a->dp[iw] & iz) == 0) {
toddouska 0:5045d2638c29 1611 return MP_NO;
toddouska 0:5045d2638c29 1612 }
toddouska 0:5045d2638c29 1613 iz <<= 1;
toddouska 0:5045d2638c29 1614 if (iz > (mp_digit)MP_MASK) {
toddouska 0:5045d2638c29 1615 ++iw;
toddouska 0:5045d2638c29 1616 iz = 1;
toddouska 0:5045d2638c29 1617 }
toddouska 0:5045d2638c29 1618 }
toddouska 0:5045d2638c29 1619 }
toddouska 0:5045d2638c29 1620 return MP_YES;
toddouska 0:5045d2638c29 1621 }
toddouska 0:5045d2638c29 1622
toddouska 0:5045d2638c29 1623
toddouska 0:5045d2638c29 1624 /* determines if a number is a valid DR modulus */
toddouska 0:5045d2638c29 1625 int mp_dr_is_modulus(mp_int *a)
toddouska 0:5045d2638c29 1626 {
toddouska 0:5045d2638c29 1627 int ix;
toddouska 0:5045d2638c29 1628
toddouska 0:5045d2638c29 1629 /* must be at least two digits */
toddouska 0:5045d2638c29 1630 if (a->used < 2) {
toddouska 0:5045d2638c29 1631 return 0;
toddouska 0:5045d2638c29 1632 }
toddouska 0:5045d2638c29 1633
toddouska 0:5045d2638c29 1634 /* must be of the form b**k - a [a <= b] so all
toddouska 0:5045d2638c29 1635 * but the first digit must be equal to -1 (mod b).
toddouska 0:5045d2638c29 1636 */
toddouska 0:5045d2638c29 1637 for (ix = 1; ix < a->used; ix++) {
toddouska 0:5045d2638c29 1638 if (a->dp[ix] != MP_MASK) {
toddouska 0:5045d2638c29 1639 return 0;
toddouska 0:5045d2638c29 1640 }
toddouska 0:5045d2638c29 1641 }
toddouska 0:5045d2638c29 1642 return 1;
toddouska 0:5045d2638c29 1643 }
toddouska 0:5045d2638c29 1644
toddouska 0:5045d2638c29 1645
toddouska 0:5045d2638c29 1646 /* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
toddouska 0:5045d2638c29 1647 *
toddouska 0:5045d2638c29 1648 * Uses a left-to-right k-ary sliding window to compute the modular
toddouska 0:5045d2638c29 1649 * exponentiation.
toddouska 0:5045d2638c29 1650 * The value of k changes based on the size of the exponent.
toddouska 0:5045d2638c29 1651 *
toddouska 0:5045d2638c29 1652 * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
toddouska 0:5045d2638c29 1653 */
toddouska 0:5045d2638c29 1654
toddouska 0:5045d2638c29 1655 #ifdef MP_LOW_MEM
toddouska 0:5045d2638c29 1656 #define TAB_SIZE 32
toddouska 0:5045d2638c29 1657 #else
toddouska 0:5045d2638c29 1658 #define TAB_SIZE 256
toddouska 0:5045d2638c29 1659 #endif
toddouska 0:5045d2638c29 1660
toddouska 0:5045d2638c29 1661 int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y,
toddouska 0:5045d2638c29 1662 int redmode)
toddouska 0:5045d2638c29 1663 {
toddouska 0:5045d2638c29 1664 mp_int M[TAB_SIZE], res;
toddouska 0:5045d2638c29 1665 mp_digit buf, mp;
toddouska 0:5045d2638c29 1666 int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
toddouska 0:5045d2638c29 1667
toddouska 0:5045d2638c29 1668 /* use a pointer to the reduction algorithm. This allows us to use
toddouska 0:5045d2638c29 1669 * one of many reduction algorithms without modding the guts of
toddouska 0:5045d2638c29 1670 * the code with if statements everywhere.
toddouska 0:5045d2638c29 1671 */
toddouska 0:5045d2638c29 1672 int (*redux)(mp_int*,mp_int*,mp_digit);
toddouska 0:5045d2638c29 1673
toddouska 0:5045d2638c29 1674 /* find window size */
toddouska 0:5045d2638c29 1675 x = mp_count_bits (X);
toddouska 0:5045d2638c29 1676 if (x <= 7) {
toddouska 0:5045d2638c29 1677 winsize = 2;
toddouska 0:5045d2638c29 1678 } else if (x <= 36) {
toddouska 0:5045d2638c29 1679 winsize = 3;
toddouska 0:5045d2638c29 1680 } else if (x <= 140) {
toddouska 0:5045d2638c29 1681 winsize = 4;
toddouska 0:5045d2638c29 1682 } else if (x <= 450) {
toddouska 0:5045d2638c29 1683 winsize = 5;
toddouska 0:5045d2638c29 1684 } else if (x <= 1303) {
toddouska 0:5045d2638c29 1685 winsize = 6;
toddouska 0:5045d2638c29 1686 } else if (x <= 3529) {
toddouska 0:5045d2638c29 1687 winsize = 7;
toddouska 0:5045d2638c29 1688 } else {
toddouska 0:5045d2638c29 1689 winsize = 8;
toddouska 0:5045d2638c29 1690 }
toddouska 0:5045d2638c29 1691
toddouska 0:5045d2638c29 1692 #ifdef MP_LOW_MEM
toddouska 0:5045d2638c29 1693 if (winsize > 5) {
toddouska 0:5045d2638c29 1694 winsize = 5;
toddouska 0:5045d2638c29 1695 }
toddouska 0:5045d2638c29 1696 #endif
toddouska 0:5045d2638c29 1697
toddouska 0:5045d2638c29 1698 /* init M array */
toddouska 0:5045d2638c29 1699 /* init first cell */
toddouska 0:5045d2638c29 1700 if ((err = mp_init(&M[1])) != MP_OKAY) {
toddouska 0:5045d2638c29 1701 return err;
toddouska 0:5045d2638c29 1702 }
toddouska 0:5045d2638c29 1703
toddouska 0:5045d2638c29 1704 /* now init the second half of the array */
toddouska 0:5045d2638c29 1705 for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
toddouska 0:5045d2638c29 1706 if ((err = mp_init(&M[x])) != MP_OKAY) {
toddouska 0:5045d2638c29 1707 for (y = 1<<(winsize-1); y < x; y++) {
toddouska 0:5045d2638c29 1708 mp_clear (&M[y]);
toddouska 0:5045d2638c29 1709 }
toddouska 0:5045d2638c29 1710 mp_clear(&M[1]);
toddouska 0:5045d2638c29 1711 return err;
toddouska 0:5045d2638c29 1712 }
toddouska 0:5045d2638c29 1713 }
toddouska 0:5045d2638c29 1714
toddouska 0:5045d2638c29 1715 /* determine and setup reduction code */
toddouska 0:5045d2638c29 1716 if (redmode == 0) {
toddouska 0:5045d2638c29 1717 #ifdef BN_MP_MONTGOMERY_SETUP_C
toddouska 0:5045d2638c29 1718 /* now setup montgomery */
toddouska 0:5045d2638c29 1719 if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
toddouska 0:5045d2638c29 1720 goto LBL_M;
toddouska 0:5045d2638c29 1721 }
toddouska 0:5045d2638c29 1722 #else
toddouska 0:5045d2638c29 1723 err = MP_VAL;
toddouska 0:5045d2638c29 1724 goto LBL_M;
toddouska 0:5045d2638c29 1725 #endif
toddouska 0:5045d2638c29 1726
toddouska 0:5045d2638c29 1727 /* automatically pick the comba one if available (saves quite a few
toddouska 0:5045d2638c29 1728 calls/ifs) */
toddouska 0:5045d2638c29 1729 #ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
toddouska 0:5045d2638c29 1730 if (((P->used * 2 + 1) < MP_WARRAY) &&
toddouska 0:5045d2638c29 1731 P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
toddouska 0:5045d2638c29 1732 redux = fast_mp_montgomery_reduce;
toddouska 0:5045d2638c29 1733 } else
toddouska 0:5045d2638c29 1734 #endif
toddouska 0:5045d2638c29 1735 {
toddouska 0:5045d2638c29 1736 #ifdef BN_MP_MONTGOMERY_REDUCE_C
toddouska 0:5045d2638c29 1737 /* use slower baseline Montgomery method */
toddouska 0:5045d2638c29 1738 redux = mp_montgomery_reduce;
toddouska 0:5045d2638c29 1739 #else
toddouska 0:5045d2638c29 1740 err = MP_VAL;
toddouska 0:5045d2638c29 1741 goto LBL_M;
toddouska 0:5045d2638c29 1742 #endif
toddouska 0:5045d2638c29 1743 }
toddouska 0:5045d2638c29 1744 } else if (redmode == 1) {
toddouska 0:5045d2638c29 1745 #if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
toddouska 0:5045d2638c29 1746 /* setup DR reduction for moduli of the form B**k - b */
toddouska 0:5045d2638c29 1747 mp_dr_setup(P, &mp);
toddouska 0:5045d2638c29 1748 redux = mp_dr_reduce;
toddouska 0:5045d2638c29 1749 #else
toddouska 0:5045d2638c29 1750 err = MP_VAL;
toddouska 0:5045d2638c29 1751 goto LBL_M;
toddouska 0:5045d2638c29 1752 #endif
toddouska 0:5045d2638c29 1753 } else {
toddouska 0:5045d2638c29 1754 #if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
toddouska 0:5045d2638c29 1755 /* setup DR reduction for moduli of the form 2**k - b */
toddouska 0:5045d2638c29 1756 if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
toddouska 0:5045d2638c29 1757 goto LBL_M;
toddouska 0:5045d2638c29 1758 }
toddouska 0:5045d2638c29 1759 redux = mp_reduce_2k;
toddouska 0:5045d2638c29 1760 #else
toddouska 0:5045d2638c29 1761 err = MP_VAL;
toddouska 0:5045d2638c29 1762 goto LBL_M;
toddouska 0:5045d2638c29 1763 #endif
toddouska 0:5045d2638c29 1764 }
toddouska 0:5045d2638c29 1765
toddouska 0:5045d2638c29 1766 /* setup result */
toddouska 0:5045d2638c29 1767 if ((err = mp_init (&res)) != MP_OKAY) {
toddouska 0:5045d2638c29 1768 goto LBL_M;
toddouska 0:5045d2638c29 1769 }
toddouska 0:5045d2638c29 1770
toddouska 0:5045d2638c29 1771 /* create M table
toddouska 0:5045d2638c29 1772 *
toddouska 0:5045d2638c29 1773
toddouska 0:5045d2638c29 1774 *
toddouska 0:5045d2638c29 1775 * The first half of the table is not computed though accept for M[0] and M[1]
toddouska 0:5045d2638c29 1776 */
toddouska 0:5045d2638c29 1777
toddouska 0:5045d2638c29 1778 if (redmode == 0) {
toddouska 0:5045d2638c29 1779 #ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
toddouska 0:5045d2638c29 1780 /* now we need R mod m */
toddouska 0:5045d2638c29 1781 if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
toddouska 0:5045d2638c29 1782 goto LBL_RES;
toddouska 0:5045d2638c29 1783 }
toddouska 0:5045d2638c29 1784 #else
toddouska 0:5045d2638c29 1785 err = MP_VAL;
toddouska 0:5045d2638c29 1786 goto LBL_RES;
toddouska 0:5045d2638c29 1787 #endif
toddouska 0:5045d2638c29 1788
toddouska 0:5045d2638c29 1789 /* now set M[1] to G * R mod m */
toddouska 0:5045d2638c29 1790 if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
toddouska 0:5045d2638c29 1791 goto LBL_RES;
toddouska 0:5045d2638c29 1792 }
toddouska 0:5045d2638c29 1793 } else {
toddouska 0:5045d2638c29 1794 mp_set(&res, 1);
toddouska 0:5045d2638c29 1795 if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
toddouska 0:5045d2638c29 1796 goto LBL_RES;
toddouska 0:5045d2638c29 1797 }
toddouska 0:5045d2638c29 1798 }
toddouska 0:5045d2638c29 1799
toddouska 0:5045d2638c29 1800 /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times*/
toddouska 0:5045d2638c29 1801 if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
toddouska 0:5045d2638c29 1802 goto LBL_RES;
toddouska 0:5045d2638c29 1803 }
toddouska 0:5045d2638c29 1804
toddouska 0:5045d2638c29 1805 for (x = 0; x < (winsize - 1); x++) {
toddouska 0:5045d2638c29 1806 if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) {
toddouska 0:5045d2638c29 1807 goto LBL_RES;
toddouska 0:5045d2638c29 1808 }
toddouska 0:5045d2638c29 1809 if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) {
toddouska 0:5045d2638c29 1810 goto LBL_RES;
toddouska 0:5045d2638c29 1811 }
toddouska 0:5045d2638c29 1812 }
toddouska 0:5045d2638c29 1813
toddouska 0:5045d2638c29 1814 /* create upper table */
toddouska 0:5045d2638c29 1815 for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
toddouska 0:5045d2638c29 1816 if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
toddouska 0:5045d2638c29 1817 goto LBL_RES;
toddouska 0:5045d2638c29 1818 }
toddouska 0:5045d2638c29 1819 if ((err = redux (&M[x], P, mp)) != MP_OKAY) {
toddouska 0:5045d2638c29 1820 goto LBL_RES;
toddouska 0:5045d2638c29 1821 }
toddouska 0:5045d2638c29 1822 }
toddouska 0:5045d2638c29 1823
toddouska 0:5045d2638c29 1824 /* set initial mode and bit cnt */
toddouska 0:5045d2638c29 1825 mode = 0;
toddouska 0:5045d2638c29 1826 bitcnt = 1;
toddouska 0:5045d2638c29 1827 buf = 0;
toddouska 0:5045d2638c29 1828 digidx = X->used - 1;
toddouska 0:5045d2638c29 1829 bitcpy = 0;
toddouska 0:5045d2638c29 1830 bitbuf = 0;
toddouska 0:5045d2638c29 1831
toddouska 0:5045d2638c29 1832 for (;;) {
toddouska 0:5045d2638c29 1833 /* grab next digit as required */
toddouska 0:5045d2638c29 1834 if (--bitcnt == 0) {
toddouska 0:5045d2638c29 1835 /* if digidx == -1 we are out of digits so break */
toddouska 0:5045d2638c29 1836 if (digidx == -1) {
toddouska 0:5045d2638c29 1837 break;
toddouska 0:5045d2638c29 1838 }
toddouska 0:5045d2638c29 1839 /* read next digit and reset bitcnt */
toddouska 0:5045d2638c29 1840 buf = X->dp[digidx--];
toddouska 0:5045d2638c29 1841 bitcnt = (int)DIGIT_BIT;
toddouska 0:5045d2638c29 1842 }
toddouska 0:5045d2638c29 1843
toddouska 0:5045d2638c29 1844 /* grab the next msb from the exponent */
toddouska 0:5045d2638c29 1845 y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
toddouska 0:5045d2638c29 1846 buf <<= (mp_digit)1;
toddouska 0:5045d2638c29 1847
toddouska 0:5045d2638c29 1848 /* if the bit is zero and mode == 0 then we ignore it
toddouska 0:5045d2638c29 1849 * These represent the leading zero bits before the first 1 bit
toddouska 0:5045d2638c29 1850 * in the exponent. Technically this opt is not required but it
toddouska 0:5045d2638c29 1851 * does lower the # of trivial squaring/reductions used
toddouska 0:5045d2638c29 1852 */
toddouska 0:5045d2638c29 1853 if (mode == 0 && y == 0) {
toddouska 0:5045d2638c29 1854 continue;
toddouska 0:5045d2638c29 1855 }
toddouska 0:5045d2638c29 1856
toddouska 0:5045d2638c29 1857 /* if the bit is zero and mode == 1 then we square */
toddouska 0:5045d2638c29 1858 if (mode == 1 && y == 0) {
toddouska 0:5045d2638c29 1859 if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
toddouska 0:5045d2638c29 1860 goto LBL_RES;
toddouska 0:5045d2638c29 1861 }
toddouska 0:5045d2638c29 1862 if ((err = redux (&res, P, mp)) != MP_OKAY) {
toddouska 0:5045d2638c29 1863 goto LBL_RES;
toddouska 0:5045d2638c29 1864 }
toddouska 0:5045d2638c29 1865 continue;
toddouska 0:5045d2638c29 1866 }
toddouska 0:5045d2638c29 1867
toddouska 0:5045d2638c29 1868 /* else we add it to the window */
toddouska 0:5045d2638c29 1869 bitbuf |= (y << (winsize - ++bitcpy));
toddouska 0:5045d2638c29 1870 mode = 2;
toddouska 0:5045d2638c29 1871
toddouska 0:5045d2638c29 1872 if (bitcpy == winsize) {
toddouska 0:5045d2638c29 1873 /* ok window is filled so square as required and multiply */
toddouska 0:5045d2638c29 1874 /* square first */
toddouska 0:5045d2638c29 1875 for (x = 0; x < winsize; x++) {
toddouska 0:5045d2638c29 1876 if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
toddouska 0:5045d2638c29 1877 goto LBL_RES;
toddouska 0:5045d2638c29 1878 }
toddouska 0:5045d2638c29 1879 if ((err = redux (&res, P, mp)) != MP_OKAY) {
toddouska 0:5045d2638c29 1880 goto LBL_RES;
toddouska 0:5045d2638c29 1881 }
toddouska 0:5045d2638c29 1882 }
toddouska 0:5045d2638c29 1883
toddouska 0:5045d2638c29 1884 /* then multiply */
toddouska 0:5045d2638c29 1885 if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
toddouska 0:5045d2638c29 1886 goto LBL_RES;
toddouska 0:5045d2638c29 1887 }
toddouska 0:5045d2638c29 1888 if ((err = redux (&res, P, mp)) != MP_OKAY) {
toddouska 0:5045d2638c29 1889 goto LBL_RES;
toddouska 0:5045d2638c29 1890 }
toddouska 0:5045d2638c29 1891
toddouska 0:5045d2638c29 1892 /* empty window and reset */
toddouska 0:5045d2638c29 1893 bitcpy = 0;
toddouska 0:5045d2638c29 1894 bitbuf = 0;
toddouska 0:5045d2638c29 1895 mode = 1;
toddouska 0:5045d2638c29 1896 }
toddouska 0:5045d2638c29 1897 }
toddouska 0:5045d2638c29 1898
toddouska 0:5045d2638c29 1899 /* if bits remain then square/multiply */
toddouska 0:5045d2638c29 1900 if (mode == 2 && bitcpy > 0) {
toddouska 0:5045d2638c29 1901 /* square then multiply if the bit is set */
toddouska 0:5045d2638c29 1902 for (x = 0; x < bitcpy; x++) {
toddouska 0:5045d2638c29 1903 if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
toddouska 0:5045d2638c29 1904 goto LBL_RES;
toddouska 0:5045d2638c29 1905 }
toddouska 0:5045d2638c29 1906 if ((err = redux (&res, P, mp)) != MP_OKAY) {
toddouska 0:5045d2638c29 1907 goto LBL_RES;
toddouska 0:5045d2638c29 1908 }
toddouska 0:5045d2638c29 1909
toddouska 0:5045d2638c29 1910 /* get next bit of the window */
toddouska 0:5045d2638c29 1911 bitbuf <<= 1;
toddouska 0:5045d2638c29 1912 if ((bitbuf & (1 << winsize)) != 0) {
toddouska 0:5045d2638c29 1913 /* then multiply */
toddouska 0:5045d2638c29 1914 if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
toddouska 0:5045d2638c29 1915 goto LBL_RES;
toddouska 0:5045d2638c29 1916 }
toddouska 0:5045d2638c29 1917 if ((err = redux (&res, P, mp)) != MP_OKAY) {
toddouska 0:5045d2638c29 1918 goto LBL_RES;
toddouska 0:5045d2638c29 1919 }
toddouska 0:5045d2638c29 1920 }
toddouska 0:5045d2638c29 1921 }
toddouska 0:5045d2638c29 1922 }
toddouska 0:5045d2638c29 1923
toddouska 0:5045d2638c29 1924 if (redmode == 0) {
toddouska 0:5045d2638c29 1925 /* fixup result if Montgomery reduction is used
toddouska 0:5045d2638c29 1926 * recall that any value in a Montgomery system is
toddouska 0:5045d2638c29 1927 * actually multiplied by R mod n. So we have
toddouska 0:5045d2638c29 1928 * to reduce one more time to cancel out the factor
toddouska 0:5045d2638c29 1929 * of R.
toddouska 0:5045d2638c29 1930 */
toddouska 0:5045d2638c29 1931 if ((err = redux(&res, P, mp)) != MP_OKAY) {
toddouska 0:5045d2638c29 1932 goto LBL_RES;
toddouska 0:5045d2638c29 1933 }
toddouska 0:5045d2638c29 1934 }
toddouska 0:5045d2638c29 1935
toddouska 0:5045d2638c29 1936 /* swap res with Y */
toddouska 0:5045d2638c29 1937 mp_exch (&res, Y);
toddouska 0:5045d2638c29 1938 err = MP_OKAY;
toddouska 0:5045d2638c29 1939 LBL_RES:mp_clear (&res);
toddouska 0:5045d2638c29 1940 LBL_M:
toddouska 0:5045d2638c29 1941 mp_clear(&M[1]);
toddouska 0:5045d2638c29 1942 for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
toddouska 0:5045d2638c29 1943 mp_clear (&M[x]);
toddouska 0:5045d2638c29 1944 }
toddouska 0:5045d2638c29 1945 return err;
toddouska 0:5045d2638c29 1946 }
toddouska 0:5045d2638c29 1947
toddouska 0:5045d2638c29 1948
toddouska 0:5045d2638c29 1949 /* setups the montgomery reduction stuff */
toddouska 0:5045d2638c29 1950 int
toddouska 0:5045d2638c29 1951 mp_montgomery_setup (mp_int * n, mp_digit * rho)
toddouska 0:5045d2638c29 1952 {
toddouska 0:5045d2638c29 1953 mp_digit x, b;
toddouska 0:5045d2638c29 1954
toddouska 0:5045d2638c29 1955 /* fast inversion mod 2**k
toddouska 0:5045d2638c29 1956 *
toddouska 0:5045d2638c29 1957 * Based on the fact that
toddouska 0:5045d2638c29 1958 *
toddouska 0:5045d2638c29 1959 * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n)
toddouska 0:5045d2638c29 1960 * => 2*X*A - X*X*A*A = 1
toddouska 0:5045d2638c29 1961 * => 2*(1) - (1) = 1
toddouska 0:5045d2638c29 1962 */
toddouska 0:5045d2638c29 1963 b = n->dp[0];
toddouska 0:5045d2638c29 1964
toddouska 0:5045d2638c29 1965 if ((b & 1) == 0) {
toddouska 0:5045d2638c29 1966 return MP_VAL;
toddouska 0:5045d2638c29 1967 }
toddouska 0:5045d2638c29 1968
toddouska 0:5045d2638c29 1969 x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
toddouska 0:5045d2638c29 1970 x *= 2 - b * x; /* here x*a==1 mod 2**8 */
toddouska 0:5045d2638c29 1971 #if !defined(MP_8BIT)
toddouska 0:5045d2638c29 1972 x *= 2 - b * x; /* here x*a==1 mod 2**16 */
toddouska 0:5045d2638c29 1973 #endif
toddouska 0:5045d2638c29 1974 #if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
toddouska 0:5045d2638c29 1975 x *= 2 - b * x; /* here x*a==1 mod 2**32 */
toddouska 0:5045d2638c29 1976 #endif
toddouska 0:5045d2638c29 1977 #ifdef MP_64BIT
toddouska 0:5045d2638c29 1978 x *= 2 - b * x; /* here x*a==1 mod 2**64 */
toddouska 0:5045d2638c29 1979 #endif
toddouska 0:5045d2638c29 1980
toddouska 0:5045d2638c29 1981 /* rho = -1/m mod b */
toddouska 0:5045d2638c29 1982 /* TAO, switched mp_word casts to mp_digit to shut up compiler */
toddouska 0:5045d2638c29 1983 *rho = (((mp_digit)1 << ((mp_digit) DIGIT_BIT)) - x) & MP_MASK;
toddouska 0:5045d2638c29 1984
toddouska 0:5045d2638c29 1985 return MP_OKAY;
toddouska 0:5045d2638c29 1986 }
toddouska 0:5045d2638c29 1987
toddouska 0:5045d2638c29 1988
toddouska 0:5045d2638c29 1989 /* computes xR**-1 == x (mod N) via Montgomery Reduction
toddouska 0:5045d2638c29 1990 *
toddouska 0:5045d2638c29 1991 * This is an optimized implementation of montgomery_reduce
toddouska 0:5045d2638c29 1992 * which uses the comba method to quickly calculate the columns of the
toddouska 0:5045d2638c29 1993 * reduction.
toddouska 0:5045d2638c29 1994 *
toddouska 0:5045d2638c29 1995 * Based on Algorithm 14.32 on pp.601 of HAC.
toddouska 0:5045d2638c29 1996 */
toddouska 0:5045d2638c29 1997 int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
toddouska 0:5045d2638c29 1998 {
toddouska 0:5045d2638c29 1999 int ix, res, olduse;
toddouska 0:5045d2638c29 2000 mp_word W[MP_WARRAY];
toddouska 0:5045d2638c29 2001
toddouska 0:5045d2638c29 2002 /* get old used count */
toddouska 0:5045d2638c29 2003 olduse = x->used;
toddouska 0:5045d2638c29 2004
toddouska 0:5045d2638c29 2005 /* grow a as required */
toddouska 0:5045d2638c29 2006 if (x->alloc < n->used + 1) {
toddouska 0:5045d2638c29 2007 if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) {
toddouska 0:5045d2638c29 2008 return res;
toddouska 0:5045d2638c29 2009 }
toddouska 0:5045d2638c29 2010 }
toddouska 0:5045d2638c29 2011
toddouska 0:5045d2638c29 2012 /* first we have to get the digits of the input into
toddouska 0:5045d2638c29 2013 * an array of double precision words W[...]
toddouska 0:5045d2638c29 2014 */
toddouska 0:5045d2638c29 2015 {
toddouska 0:5045d2638c29 2016 register mp_word *_W;
toddouska 0:5045d2638c29 2017 register mp_digit *tmpx;
toddouska 0:5045d2638c29 2018
toddouska 0:5045d2638c29 2019 /* alias for the W[] array */
toddouska 0:5045d2638c29 2020 _W = W;
toddouska 0:5045d2638c29 2021
toddouska 0:5045d2638c29 2022 /* alias for the digits of x*/
toddouska 0:5045d2638c29 2023 tmpx = x->dp;
toddouska 0:5045d2638c29 2024
toddouska 0:5045d2638c29 2025 /* copy the digits of a into W[0..a->used-1] */
toddouska 0:5045d2638c29 2026 for (ix = 0; ix < x->used; ix++) {
toddouska 0:5045d2638c29 2027 *_W++ = *tmpx++;
toddouska 0:5045d2638c29 2028 }
toddouska 0:5045d2638c29 2029
toddouska 0:5045d2638c29 2030 /* zero the high words of W[a->used..m->used*2] */
toddouska 0:5045d2638c29 2031 for (; ix < n->used * 2 + 1; ix++) {
toddouska 0:5045d2638c29 2032 *_W++ = 0;
toddouska 0:5045d2638c29 2033 }
toddouska 0:5045d2638c29 2034 }
toddouska 0:5045d2638c29 2035
toddouska 0:5045d2638c29 2036 /* now we proceed to zero successive digits
toddouska 0:5045d2638c29 2037 * from the least significant upwards
toddouska 0:5045d2638c29 2038 */
toddouska 0:5045d2638c29 2039 for (ix = 0; ix < n->used; ix++) {
toddouska 0:5045d2638c29 2040 /* mu = ai * m' mod b
toddouska 0:5045d2638c29 2041 *
toddouska 0:5045d2638c29 2042 * We avoid a double precision multiplication (which isn't required)
toddouska 0:5045d2638c29 2043 * by casting the value down to a mp_digit. Note this requires
toddouska 0:5045d2638c29 2044 * that W[ix-1] have the carry cleared (see after the inner loop)
toddouska 0:5045d2638c29 2045 */
toddouska 0:5045d2638c29 2046 register mp_digit mu;
toddouska 0:5045d2638c29 2047 mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
toddouska 0:5045d2638c29 2048
toddouska 0:5045d2638c29 2049 /* a = a + mu * m * b**i
toddouska 0:5045d2638c29 2050 *
toddouska 0:5045d2638c29 2051 * This is computed in place and on the fly. The multiplication
toddouska 0:5045d2638c29 2052 * by b**i is handled by offseting which columns the results
toddouska 0:5045d2638c29 2053 * are added to.
toddouska 0:5045d2638c29 2054 *
toddouska 0:5045d2638c29 2055 * Note the comba method normally doesn't handle carries in the
toddouska 0:5045d2638c29 2056 * inner loop In this case we fix the carry from the previous
toddouska 0:5045d2638c29 2057 * column since the Montgomery reduction requires digits of the
toddouska 0:5045d2638c29 2058 * result (so far) [see above] to work. This is
toddouska 0:5045d2638c29 2059 * handled by fixing up one carry after the inner loop. The
toddouska 0:5045d2638c29 2060 * carry fixups are done in order so after these loops the
toddouska 0:5045d2638c29 2061 * first m->used words of W[] have the carries fixed
toddouska 0:5045d2638c29 2062 */
toddouska 0:5045d2638c29 2063 {
toddouska 0:5045d2638c29 2064 register int iy;
toddouska 0:5045d2638c29 2065 register mp_digit *tmpn;
toddouska 0:5045d2638c29 2066 register mp_word *_W;
toddouska 0:5045d2638c29 2067
toddouska 0:5045d2638c29 2068 /* alias for the digits of the modulus */
toddouska 0:5045d2638c29 2069 tmpn = n->dp;
toddouska 0:5045d2638c29 2070
toddouska 0:5045d2638c29 2071 /* Alias for the columns set by an offset of ix */
toddouska 0:5045d2638c29 2072 _W = W + ix;
toddouska 0:5045d2638c29 2073
toddouska 0:5045d2638c29 2074 /* inner loop */
toddouska 0:5045d2638c29 2075 for (iy = 0; iy < n->used; iy++) {
toddouska 0:5045d2638c29 2076 *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
toddouska 0:5045d2638c29 2077 }
toddouska 0:5045d2638c29 2078 }
toddouska 0:5045d2638c29 2079
toddouska 0:5045d2638c29 2080 /* now fix carry for next digit, W[ix+1] */
toddouska 0:5045d2638c29 2081 W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
toddouska 0:5045d2638c29 2082 }
toddouska 0:5045d2638c29 2083
toddouska 0:5045d2638c29 2084 /* now we have to propagate the carries and
toddouska 0:5045d2638c29 2085 * shift the words downward [all those least
toddouska 0:5045d2638c29 2086 * significant digits we zeroed].
toddouska 0:5045d2638c29 2087 */
toddouska 0:5045d2638c29 2088 {
toddouska 0:5045d2638c29 2089 register mp_digit *tmpx;
toddouska 0:5045d2638c29 2090 register mp_word *_W, *_W1;
toddouska 0:5045d2638c29 2091
toddouska 0:5045d2638c29 2092 /* nox fix rest of carries */
toddouska 0:5045d2638c29 2093
toddouska 0:5045d2638c29 2094 /* alias for current word */
toddouska 0:5045d2638c29 2095 _W1 = W + ix;
toddouska 0:5045d2638c29 2096
toddouska 0:5045d2638c29 2097 /* alias for next word, where the carry goes */
toddouska 0:5045d2638c29 2098 _W = W + ++ix;
toddouska 0:5045d2638c29 2099
toddouska 0:5045d2638c29 2100 for (; ix <= n->used * 2 + 1; ix++) {
toddouska 0:5045d2638c29 2101 *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
toddouska 0:5045d2638c29 2102 }
toddouska 0:5045d2638c29 2103
toddouska 0:5045d2638c29 2104 /* copy out, A = A/b**n
toddouska 0:5045d2638c29 2105 *
toddouska 0:5045d2638c29 2106 * The result is A/b**n but instead of converting from an
toddouska 0:5045d2638c29 2107 * array of mp_word to mp_digit than calling mp_rshd
toddouska 0:5045d2638c29 2108 * we just copy them in the right order
toddouska 0:5045d2638c29 2109 */
toddouska 0:5045d2638c29 2110
toddouska 0:5045d2638c29 2111 /* alias for destination word */
toddouska 0:5045d2638c29 2112 tmpx = x->dp;
toddouska 0:5045d2638c29 2113
toddouska 0:5045d2638c29 2114 /* alias for shifted double precision result */
toddouska 0:5045d2638c29 2115 _W = W + n->used;
toddouska 0:5045d2638c29 2116
toddouska 0:5045d2638c29 2117 for (ix = 0; ix < n->used + 1; ix++) {
toddouska 0:5045d2638c29 2118 *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
toddouska 0:5045d2638c29 2119 }
toddouska 0:5045d2638c29 2120
toddouska 0:5045d2638c29 2121 /* zero oldused digits, if the input a was larger than
toddouska 0:5045d2638c29 2122 * m->used+1 we'll have to clear the digits
toddouska 0:5045d2638c29 2123 */
toddouska 0:5045d2638c29 2124 for (; ix < olduse; ix++) {
toddouska 0:5045d2638c29 2125 *tmpx++ = 0;
toddouska 0:5045d2638c29 2126 }
toddouska 0:5045d2638c29 2127 }
toddouska 0:5045d2638c29 2128
toddouska 0:5045d2638c29 2129 /* set the max used and clamp */
toddouska 0:5045d2638c29 2130 x->used = n->used + 1;
toddouska 0:5045d2638c29 2131 mp_clamp (x);
toddouska 0:5045d2638c29 2132
toddouska 0:5045d2638c29 2133 /* if A >= m then A = A - m */
toddouska 0:5045d2638c29 2134 if (mp_cmp_mag (x, n) != MP_LT) {
toddouska 0:5045d2638c29 2135 return s_mp_sub (x, n, x);
toddouska 0:5045d2638c29 2136 }
toddouska 0:5045d2638c29 2137 return MP_OKAY;
toddouska 0:5045d2638c29 2138 }
toddouska 0:5045d2638c29 2139
toddouska 0:5045d2638c29 2140
toddouska 0:5045d2638c29 2141 /* computes xR**-1 == x (mod N) via Montgomery Reduction */
toddouska 0:5045d2638c29 2142 int
toddouska 0:5045d2638c29 2143 mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
toddouska 0:5045d2638c29 2144 {
toddouska 0:5045d2638c29 2145 int ix, res, digs;
toddouska 0:5045d2638c29 2146 mp_digit mu;
toddouska 0:5045d2638c29 2147
toddouska 0:5045d2638c29 2148 /* can the fast reduction [comba] method be used?
toddouska 0:5045d2638c29 2149 *
toddouska 0:5045d2638c29 2150 * Note that unlike in mul you're safely allowed *less*
toddouska 0:5045d2638c29 2151 * than the available columns [255 per default] since carries
toddouska 0:5045d2638c29 2152 * are fixed up in the inner loop.
toddouska 0:5045d2638c29 2153 */
toddouska 0:5045d2638c29 2154 digs = n->used * 2 + 1;
toddouska 0:5045d2638c29 2155 if ((digs < MP_WARRAY) &&
toddouska 0:5045d2638c29 2156 n->used <
toddouska 0:5045d2638c29 2157 (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
toddouska 0:5045d2638c29 2158 return fast_mp_montgomery_reduce (x, n, rho);
toddouska 0:5045d2638c29 2159 }
toddouska 0:5045d2638c29 2160
toddouska 0:5045d2638c29 2161 /* grow the input as required */
toddouska 0:5045d2638c29 2162 if (x->alloc < digs) {
toddouska 0:5045d2638c29 2163 if ((res = mp_grow (x, digs)) != MP_OKAY) {
toddouska 0:5045d2638c29 2164 return res;
toddouska 0:5045d2638c29 2165 }
toddouska 0:5045d2638c29 2166 }
toddouska 0:5045d2638c29 2167 x->used = digs;
toddouska 0:5045d2638c29 2168
toddouska 0:5045d2638c29 2169 for (ix = 0; ix < n->used; ix++) {
toddouska 0:5045d2638c29 2170 /* mu = ai * rho mod b
toddouska 0:5045d2638c29 2171 *
toddouska 0:5045d2638c29 2172 * The value of rho must be precalculated via
toddouska 0:5045d2638c29 2173 * montgomery_setup() such that
toddouska 0:5045d2638c29 2174 * it equals -1/n0 mod b this allows the
toddouska 0:5045d2638c29 2175 * following inner loop to reduce the
toddouska 0:5045d2638c29 2176 * input one digit at a time
toddouska 0:5045d2638c29 2177 */
toddouska 0:5045d2638c29 2178 mu = (mp_digit) (((mp_word)x->dp[ix]) * ((mp_word)rho) & MP_MASK);
toddouska 0:5045d2638c29 2179
toddouska 0:5045d2638c29 2180 /* a = a + mu * m * b**i */
toddouska 0:5045d2638c29 2181 {
toddouska 0:5045d2638c29 2182 register int iy;
toddouska 0:5045d2638c29 2183 register mp_digit *tmpn, *tmpx, u;
toddouska 0:5045d2638c29 2184 register mp_word r;
toddouska 0:5045d2638c29 2185
toddouska 0:5045d2638c29 2186 /* alias for digits of the modulus */
toddouska 0:5045d2638c29 2187 tmpn = n->dp;
toddouska 0:5045d2638c29 2188
toddouska 0:5045d2638c29 2189 /* alias for the digits of x [the input] */
toddouska 0:5045d2638c29 2190 tmpx = x->dp + ix;
toddouska 0:5045d2638c29 2191
toddouska 0:5045d2638c29 2192 /* set the carry to zero */
toddouska 0:5045d2638c29 2193 u = 0;
toddouska 0:5045d2638c29 2194
toddouska 0:5045d2638c29 2195 /* Multiply and add in place */
toddouska 0:5045d2638c29 2196 for (iy = 0; iy < n->used; iy++) {
toddouska 0:5045d2638c29 2197 /* compute product and sum */
toddouska 0:5045d2638c29 2198 r = ((mp_word)mu) * ((mp_word)*tmpn++) +
toddouska 0:5045d2638c29 2199 ((mp_word) u) + ((mp_word) * tmpx);
toddouska 0:5045d2638c29 2200
toddouska 0:5045d2638c29 2201 /* get carry */
toddouska 0:5045d2638c29 2202 u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
toddouska 0:5045d2638c29 2203
toddouska 0:5045d2638c29 2204 /* fix digit */
toddouska 0:5045d2638c29 2205 *tmpx++ = (mp_digit)(r & ((mp_word) MP_MASK));
toddouska 0:5045d2638c29 2206 }
toddouska 0:5045d2638c29 2207 /* At this point the ix'th digit of x should be zero */
toddouska 0:5045d2638c29 2208
toddouska 0:5045d2638c29 2209
toddouska 0:5045d2638c29 2210 /* propagate carries upwards as required*/
toddouska 0:5045d2638c29 2211 while (u) {
toddouska 0:5045d2638c29 2212 *tmpx += u;
toddouska 0:5045d2638c29 2213 u = *tmpx >> DIGIT_BIT;
toddouska 0:5045d2638c29 2214 *tmpx++ &= MP_MASK;
toddouska 0:5045d2638c29 2215 }
toddouska 0:5045d2638c29 2216 }
toddouska 0:5045d2638c29 2217 }
toddouska 0:5045d2638c29 2218
toddouska 0:5045d2638c29 2219 /* at this point the n.used'th least
toddouska 0:5045d2638c29 2220 * significant digits of x are all zero
toddouska 0:5045d2638c29 2221 * which means we can shift x to the
toddouska 0:5045d2638c29 2222 * right by n.used digits and the
toddouska 0:5045d2638c29 2223 * residue is unchanged.
toddouska 0:5045d2638c29 2224 */
toddouska 0:5045d2638c29 2225
toddouska 0:5045d2638c29 2226 /* x = x/b**n.used */
toddouska 0:5045d2638c29 2227 mp_clamp(x);
toddouska 0:5045d2638c29 2228 mp_rshd (x, n->used);
toddouska 0:5045d2638c29 2229
toddouska 0:5045d2638c29 2230 /* if x >= n then x = x - n */
toddouska 0:5045d2638c29 2231 if (mp_cmp_mag (x, n) != MP_LT) {
toddouska 0:5045d2638c29 2232 return s_mp_sub (x, n, x);
toddouska 0:5045d2638c29 2233 }
toddouska 0:5045d2638c29 2234
toddouska 0:5045d2638c29 2235 return MP_OKAY;
toddouska 0:5045d2638c29 2236 }
toddouska 0:5045d2638c29 2237
toddouska 0:5045d2638c29 2238
toddouska 0:5045d2638c29 2239 /* determines the setup value */
toddouska 0:5045d2638c29 2240 void mp_dr_setup(mp_int *a, mp_digit *d)
toddouska 0:5045d2638c29 2241 {
toddouska 0:5045d2638c29 2242 /* the casts are required if DIGIT_BIT is one less than
toddouska 0:5045d2638c29 2243 * the number of bits in a mp_digit [e.g. DIGIT_BIT==31]
toddouska 0:5045d2638c29 2244 */
toddouska 0:5045d2638c29 2245 *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) -
toddouska 0:5045d2638c29 2246 ((mp_word)a->dp[0]));
toddouska 0:5045d2638c29 2247 }
toddouska 0:5045d2638c29 2248
toddouska 0:5045d2638c29 2249
toddouska 0:5045d2638c29 2250 /* reduce "x" in place modulo "n" using the Diminished Radix algorithm.
toddouska 0:5045d2638c29 2251 *
toddouska 0:5045d2638c29 2252 * Based on algorithm from the paper
toddouska 0:5045d2638c29 2253 *
toddouska 0:5045d2638c29 2254 * "Generating Efficient Primes for Discrete Log Cryptosystems"
toddouska 0:5045d2638c29 2255 * Chae Hoon Lim, Pil Joong Lee,
toddouska 0:5045d2638c29 2256 * POSTECH Information Research Laboratories
toddouska 0:5045d2638c29 2257 *
toddouska 0:5045d2638c29 2258 * The modulus must be of a special format [see manual]
toddouska 0:5045d2638c29 2259 *
toddouska 0:5045d2638c29 2260 * Has been modified to use algorithm 7.10 from the LTM book instead
toddouska 0:5045d2638c29 2261 *
toddouska 0:5045d2638c29 2262 * Input x must be in the range 0 <= x <= (n-1)**2
toddouska 0:5045d2638c29 2263 */
toddouska 0:5045d2638c29 2264 int
toddouska 0:5045d2638c29 2265 mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k)
toddouska 0:5045d2638c29 2266 {
toddouska 0:5045d2638c29 2267 int err, i, m;
toddouska 0:5045d2638c29 2268 mp_word r;
toddouska 0:5045d2638c29 2269 mp_digit mu, *tmpx1, *tmpx2;
toddouska 0:5045d2638c29 2270
toddouska 0:5045d2638c29 2271 /* m = digits in modulus */
toddouska 0:5045d2638c29 2272 m = n->used;
toddouska 0:5045d2638c29 2273
toddouska 0:5045d2638c29 2274 /* ensure that "x" has at least 2m digits */
toddouska 0:5045d2638c29 2275 if (x->alloc < m + m) {
toddouska 0:5045d2638c29 2276 if ((err = mp_grow (x, m + m)) != MP_OKAY) {
toddouska 0:5045d2638c29 2277 return err;
toddouska 0:5045d2638c29 2278 }
toddouska 0:5045d2638c29 2279 }
toddouska 0:5045d2638c29 2280
toddouska 0:5045d2638c29 2281 /* top of loop, this is where the code resumes if
toddouska 0:5045d2638c29 2282 * another reduction pass is required.
toddouska 0:5045d2638c29 2283 */
toddouska 0:5045d2638c29 2284 top:
toddouska 0:5045d2638c29 2285 /* aliases for digits */
toddouska 0:5045d2638c29 2286 /* alias for lower half of x */
toddouska 0:5045d2638c29 2287 tmpx1 = x->dp;
toddouska 0:5045d2638c29 2288
toddouska 0:5045d2638c29 2289 /* alias for upper half of x, or x/B**m */
toddouska 0:5045d2638c29 2290 tmpx2 = x->dp + m;
toddouska 0:5045d2638c29 2291
toddouska 0:5045d2638c29 2292 /* set carry to zero */
toddouska 0:5045d2638c29 2293 mu = 0;
toddouska 0:5045d2638c29 2294
toddouska 0:5045d2638c29 2295 /* compute (x mod B**m) + k * [x/B**m] inline and inplace */
toddouska 0:5045d2638c29 2296 for (i = 0; i < m; i++) {
toddouska 0:5045d2638c29 2297 r = ((mp_word)*tmpx2++) * ((mp_word)k) + *tmpx1 + mu;
toddouska 0:5045d2638c29 2298 *tmpx1++ = (mp_digit)(r & MP_MASK);
toddouska 0:5045d2638c29 2299 mu = (mp_digit)(r >> ((mp_word)DIGIT_BIT));
toddouska 0:5045d2638c29 2300 }
toddouska 0:5045d2638c29 2301
toddouska 0:5045d2638c29 2302 /* set final carry */
toddouska 0:5045d2638c29 2303 *tmpx1++ = mu;
toddouska 0:5045d2638c29 2304
toddouska 0:5045d2638c29 2305 /* zero words above m */
toddouska 0:5045d2638c29 2306 for (i = m + 1; i < x->used; i++) {
toddouska 0:5045d2638c29 2307 *tmpx1++ = 0;
toddouska 0:5045d2638c29 2308 }
toddouska 0:5045d2638c29 2309
toddouska 0:5045d2638c29 2310 /* clamp, sub and return */
toddouska 0:5045d2638c29 2311 mp_clamp (x);
toddouska 0:5045d2638c29 2312
toddouska 0:5045d2638c29 2313 /* if x >= n then subtract and reduce again
toddouska 0:5045d2638c29 2314 * Each successive "recursion" makes the input smaller and smaller.
toddouska 0:5045d2638c29 2315 */
toddouska 0:5045d2638c29 2316 if (mp_cmp_mag (x, n) != MP_LT) {
toddouska 0:5045d2638c29 2317 s_mp_sub(x, n, x);
toddouska 0:5045d2638c29 2318 goto top;
toddouska 0:5045d2638c29 2319 }
toddouska 0:5045d2638c29 2320 return MP_OKAY;
toddouska 0:5045d2638c29 2321 }
toddouska 0:5045d2638c29 2322
toddouska 0:5045d2638c29 2323
toddouska 0:5045d2638c29 2324 /* reduces a modulo n where n is of the form 2**p - d */
toddouska 0:5045d2638c29 2325 int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d)
toddouska 0:5045d2638c29 2326 {
toddouska 0:5045d2638c29 2327 mp_int q;
toddouska 0:5045d2638c29 2328 int p, res;
toddouska 0:5045d2638c29 2329
toddouska 0:5045d2638c29 2330 if ((res = mp_init(&q)) != MP_OKAY) {
toddouska 0:5045d2638c29 2331 return res;
toddouska 0:5045d2638c29 2332 }
toddouska 0:5045d2638c29 2333
toddouska 0:5045d2638c29 2334 p = mp_count_bits(n);
toddouska 0:5045d2638c29 2335 top:
toddouska 0:5045d2638c29 2336 /* q = a/2**p, a = a mod 2**p */
toddouska 0:5045d2638c29 2337 if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
toddouska 0:5045d2638c29 2338 goto ERR;
toddouska 0:5045d2638c29 2339 }
toddouska 0:5045d2638c29 2340
toddouska 0:5045d2638c29 2341 if (d != 1) {
toddouska 0:5045d2638c29 2342 /* q = q * d */
toddouska 0:5045d2638c29 2343 if ((res = mp_mul_d(&q, d, &q)) != MP_OKAY) {
toddouska 0:5045d2638c29 2344 goto ERR;
toddouska 0:5045d2638c29 2345 }
toddouska 0:5045d2638c29 2346 }
toddouska 0:5045d2638c29 2347
toddouska 0:5045d2638c29 2348 /* a = a + q */
toddouska 0:5045d2638c29 2349 if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
toddouska 0:5045d2638c29 2350 goto ERR;
toddouska 0:5045d2638c29 2351 }
toddouska 0:5045d2638c29 2352
toddouska 0:5045d2638c29 2353 if (mp_cmp_mag(a, n) != MP_LT) {
toddouska 0:5045d2638c29 2354 s_mp_sub(a, n, a);
toddouska 0:5045d2638c29 2355 goto top;
toddouska 0:5045d2638c29 2356 }
toddouska 0:5045d2638c29 2357
toddouska 0:5045d2638c29 2358 ERR:
toddouska 0:5045d2638c29 2359 mp_clear(&q);
toddouska 0:5045d2638c29 2360 return res;
toddouska 0:5045d2638c29 2361 }
toddouska 0:5045d2638c29 2362
toddouska 0:5045d2638c29 2363
toddouska 0:5045d2638c29 2364 /* determines the setup value */
toddouska 0:5045d2638c29 2365 int mp_reduce_2k_setup(mp_int *a, mp_digit *d)
toddouska 0:5045d2638c29 2366 {
toddouska 0:5045d2638c29 2367 int res, p;
toddouska 0:5045d2638c29 2368 mp_int tmp;
toddouska 0:5045d2638c29 2369
toddouska 0:5045d2638c29 2370 if ((res = mp_init(&tmp)) != MP_OKAY) {
toddouska 0:5045d2638c29 2371 return res;
toddouska 0:5045d2638c29 2372 }
toddouska 0:5045d2638c29 2373
toddouska 0:5045d2638c29 2374 p = mp_count_bits(a);
toddouska 0:5045d2638c29 2375 if ((res = mp_2expt(&tmp, p)) != MP_OKAY) {
toddouska 0:5045d2638c29 2376 mp_clear(&tmp);
toddouska 0:5045d2638c29 2377 return res;
toddouska 0:5045d2638c29 2378 }
toddouska 0:5045d2638c29 2379
toddouska 0:5045d2638c29 2380 if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) {
toddouska 0:5045d2638c29 2381 mp_clear(&tmp);
toddouska 0:5045d2638c29 2382 return res;
toddouska 0:5045d2638c29 2383 }
toddouska 0:5045d2638c29 2384
toddouska 0:5045d2638c29 2385 *d = tmp.dp[0];
toddouska 0:5045d2638c29 2386 mp_clear(&tmp);
toddouska 0:5045d2638c29 2387 return MP_OKAY;
toddouska 0:5045d2638c29 2388 }
toddouska 0:5045d2638c29 2389
toddouska 0:5045d2638c29 2390
toddouska 0:5045d2638c29 2391 /* computes a = 2**b
toddouska 0:5045d2638c29 2392 *
toddouska 0:5045d2638c29 2393 * Simple algorithm which zeroes the int, grows it then just sets one bit
toddouska 0:5045d2638c29 2394 * as required.
toddouska 0:5045d2638c29 2395 */
toddouska 0:5045d2638c29 2396 int
toddouska 0:5045d2638c29 2397 mp_2expt (mp_int * a, int b)
toddouska 0:5045d2638c29 2398 {
toddouska 0:5045d2638c29 2399 int res;
toddouska 0:5045d2638c29 2400
toddouska 0:5045d2638c29 2401 /* zero a as per default */
toddouska 0:5045d2638c29 2402 mp_zero (a);
toddouska 0:5045d2638c29 2403
toddouska 0:5045d2638c29 2404 /* grow a to accomodate the single bit */
toddouska 0:5045d2638c29 2405 if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
toddouska 0:5045d2638c29 2406 return res;
toddouska 0:5045d2638c29 2407 }
toddouska 0:5045d2638c29 2408
toddouska 0:5045d2638c29 2409 /* set the used count of where the bit will go */
toddouska 0:5045d2638c29 2410 a->used = b / DIGIT_BIT + 1;
toddouska 0:5045d2638c29 2411
toddouska 0:5045d2638c29 2412 /* put the single bit in its place */
toddouska 0:5045d2638c29 2413 a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT);
toddouska 0:5045d2638c29 2414
toddouska 0:5045d2638c29 2415 return MP_OKAY;
toddouska 0:5045d2638c29 2416 }
toddouska 0:5045d2638c29 2417
toddouska 0:5045d2638c29 2418
toddouska 0:5045d2638c29 2419 /* multiply by a digit */
toddouska 0:5045d2638c29 2420 int
toddouska 0:5045d2638c29 2421 mp_mul_d (mp_int * a, mp_digit b, mp_int * c)
toddouska 0:5045d2638c29 2422 {
toddouska 0:5045d2638c29 2423 mp_digit u, *tmpa, *tmpc;
toddouska 0:5045d2638c29 2424 mp_word r;
toddouska 0:5045d2638c29 2425 int ix, res, olduse;
toddouska 0:5045d2638c29 2426
toddouska 0:5045d2638c29 2427 /* make sure c is big enough to hold a*b */
toddouska 0:5045d2638c29 2428 if (c->alloc < a->used + 1) {
toddouska 0:5045d2638c29 2429 if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
toddouska 0:5045d2638c29 2430 return res;
toddouska 0:5045d2638c29 2431 }
toddouska 0:5045d2638c29 2432 }
toddouska 0:5045d2638c29 2433
toddouska 0:5045d2638c29 2434 /* get the original destinations used count */
toddouska 0:5045d2638c29 2435 olduse = c->used;
toddouska 0:5045d2638c29 2436
toddouska 0:5045d2638c29 2437 /* set the sign */
toddouska 0:5045d2638c29 2438 c->sign = a->sign;
toddouska 0:5045d2638c29 2439
toddouska 0:5045d2638c29 2440 /* alias for a->dp [source] */
toddouska 0:5045d2638c29 2441 tmpa = a->dp;
toddouska 0:5045d2638c29 2442
toddouska 0:5045d2638c29 2443 /* alias for c->dp [dest] */
toddouska 0:5045d2638c29 2444 tmpc = c->dp;
toddouska 0:5045d2638c29 2445
toddouska 0:5045d2638c29 2446 /* zero carry */
toddouska 0:5045d2638c29 2447 u = 0;
toddouska 0:5045d2638c29 2448
toddouska 0:5045d2638c29 2449 /* compute columns */
toddouska 0:5045d2638c29 2450 for (ix = 0; ix < a->used; ix++) {
toddouska 0:5045d2638c29 2451 /* compute product and carry sum for this term */
toddouska 0:5045d2638c29 2452 r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
toddouska 0:5045d2638c29 2453
toddouska 0:5045d2638c29 2454 /* mask off higher bits to get a single digit */
toddouska 0:5045d2638c29 2455 *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
toddouska 0:5045d2638c29 2456
toddouska 0:5045d2638c29 2457 /* send carry into next iteration */
toddouska 0:5045d2638c29 2458 u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
toddouska 0:5045d2638c29 2459 }
toddouska 0:5045d2638c29 2460
toddouska 0:5045d2638c29 2461 /* store final carry [if any] and increment ix offset */
toddouska 0:5045d2638c29 2462 *tmpc++ = u;
toddouska 0:5045d2638c29 2463 ++ix;
toddouska 0:5045d2638c29 2464
toddouska 0:5045d2638c29 2465 /* now zero digits above the top */
toddouska 0:5045d2638c29 2466 while (ix++ < olduse) {
toddouska 0:5045d2638c29 2467 *tmpc++ = 0;
toddouska 0:5045d2638c29 2468 }
toddouska 0:5045d2638c29 2469
toddouska 0:5045d2638c29 2470 /* set used count */
toddouska 0:5045d2638c29 2471 c->used = a->used + 1;
toddouska 0:5045d2638c29 2472 mp_clamp(c);
toddouska 0:5045d2638c29 2473
toddouska 0:5045d2638c29 2474 return MP_OKAY;
toddouska 0:5045d2638c29 2475 }
toddouska 0:5045d2638c29 2476
toddouska 0:5045d2638c29 2477
toddouska 0:5045d2638c29 2478 /* d = a * b (mod c) */
toddouska 0:5045d2638c29 2479 int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
toddouska 0:5045d2638c29 2480 {
toddouska 0:5045d2638c29 2481 int res;
toddouska 0:5045d2638c29 2482 mp_int t;
toddouska 0:5045d2638c29 2483
toddouska 0:5045d2638c29 2484 if ((res = mp_init (&t)) != MP_OKAY) {
toddouska 0:5045d2638c29 2485 return res;
toddouska 0:5045d2638c29 2486 }
toddouska 0:5045d2638c29 2487
toddouska 0:5045d2638c29 2488 if ((res = mp_mul (a, b, &t)) != MP_OKAY) {
toddouska 0:5045d2638c29 2489 mp_clear (&t);
toddouska 0:5045d2638c29 2490 return res;
toddouska 0:5045d2638c29 2491 }
toddouska 0:5045d2638c29 2492 res = mp_mod (&t, c, d);
toddouska 0:5045d2638c29 2493 mp_clear (&t);
toddouska 0:5045d2638c29 2494 return res;
toddouska 0:5045d2638c29 2495 }
toddouska 0:5045d2638c29 2496
toddouska 0:5045d2638c29 2497
toddouska 0:5045d2638c29 2498 /* computes b = a*a */
toddouska 0:5045d2638c29 2499 int
toddouska 0:5045d2638c29 2500 mp_sqr (mp_int * a, mp_int * b)
toddouska 0:5045d2638c29 2501 {
toddouska 0:5045d2638c29 2502 int res;
toddouska 0:5045d2638c29 2503
toddouska 0:5045d2638c29 2504 {
toddouska 0:5045d2638c29 2505 #ifdef BN_FAST_S_MP_SQR_C
toddouska 0:5045d2638c29 2506 /* can we use the fast comba multiplier? */
toddouska 0:5045d2638c29 2507 if ((a->used * 2 + 1) < MP_WARRAY &&
toddouska 0:5045d2638c29 2508 a->used <
toddouska 0:5045d2638c29 2509 (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
toddouska 0:5045d2638c29 2510 res = fast_s_mp_sqr (a, b);
toddouska 0:5045d2638c29 2511 } else
toddouska 0:5045d2638c29 2512 #endif
toddouska 0:5045d2638c29 2513 #ifdef BN_S_MP_SQR_C
toddouska 0:5045d2638c29 2514 res = s_mp_sqr (a, b);
toddouska 0:5045d2638c29 2515 #else
toddouska 0:5045d2638c29 2516 res = MP_VAL;
toddouska 0:5045d2638c29 2517 #endif
toddouska 0:5045d2638c29 2518 }
toddouska 0:5045d2638c29 2519 b->sign = MP_ZPOS;
toddouska 0:5045d2638c29 2520 return res;
toddouska 0:5045d2638c29 2521 }
toddouska 0:5045d2638c29 2522
toddouska 0:5045d2638c29 2523
toddouska 0:5045d2638c29 2524 /* high level multiplication (handles sign) */
toddouska 0:5045d2638c29 2525 int mp_mul (mp_int * a, mp_int * b, mp_int * c)
toddouska 0:5045d2638c29 2526 {
toddouska 0:5045d2638c29 2527 int res, neg;
toddouska 0:5045d2638c29 2528 neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
toddouska 0:5045d2638c29 2529
toddouska 0:5045d2638c29 2530 {
toddouska 0:5045d2638c29 2531 /* can we use the fast multiplier?
toddouska 0:5045d2638c29 2532 *
toddouska 0:5045d2638c29 2533 * The fast multiplier can be used if the output will
toddouska 0:5045d2638c29 2534 * have less than MP_WARRAY digits and the number of
toddouska 0:5045d2638c29 2535 * digits won't affect carry propagation
toddouska 0:5045d2638c29 2536 */
toddouska 0:5045d2638c29 2537 int digs = a->used + b->used + 1;
toddouska 0:5045d2638c29 2538
toddouska 0:5045d2638c29 2539 #ifdef BN_FAST_S_MP_MUL_DIGS_C
toddouska 0:5045d2638c29 2540 if ((digs < MP_WARRAY) &&
toddouska 0:5045d2638c29 2541 MIN(a->used, b->used) <=
toddouska 0:5045d2638c29 2542 (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
toddouska 0:5045d2638c29 2543 res = fast_s_mp_mul_digs (a, b, c, digs);
toddouska 0:5045d2638c29 2544 } else
toddouska 0:5045d2638c29 2545 #endif
toddouska 0:5045d2638c29 2546 #ifdef BN_S_MP_MUL_DIGS_C
toddouska 0:5045d2638c29 2547 res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
toddouska 0:5045d2638c29 2548 #else
toddouska 0:5045d2638c29 2549 res = MP_VAL;
toddouska 0:5045d2638c29 2550 #endif
toddouska 0:5045d2638c29 2551
toddouska 0:5045d2638c29 2552 }
toddouska 0:5045d2638c29 2553 c->sign = (c->used > 0) ? neg : MP_ZPOS;
toddouska 0:5045d2638c29 2554 return res;
toddouska 0:5045d2638c29 2555 }
toddouska 0:5045d2638c29 2556
toddouska 0:5045d2638c29 2557
toddouska 0:5045d2638c29 2558 /* b = a*2 */
toddouska 0:5045d2638c29 2559 int mp_mul_2(mp_int * a, mp_int * b)
toddouska 0:5045d2638c29 2560 {
toddouska 0:5045d2638c29 2561 int x, res, oldused;
toddouska 0:5045d2638c29 2562
toddouska 0:5045d2638c29 2563 /* grow to accomodate result */
toddouska 0:5045d2638c29 2564 if (b->alloc < a->used + 1) {
toddouska 0:5045d2638c29 2565 if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
toddouska 0:5045d2638c29 2566 return res;
toddouska 0:5045d2638c29 2567 }
toddouska 0:5045d2638c29 2568 }
toddouska 0:5045d2638c29 2569
toddouska 0:5045d2638c29 2570 oldused = b->used;
toddouska 0:5045d2638c29 2571 b->used = a->used;
toddouska 0:5045d2638c29 2572
toddouska 0:5045d2638c29 2573 {
toddouska 0:5045d2638c29 2574 register mp_digit r, rr, *tmpa, *tmpb;
toddouska 0:5045d2638c29 2575
toddouska 0:5045d2638c29 2576 /* alias for source */
toddouska 0:5045d2638c29 2577 tmpa = a->dp;
toddouska 0:5045d2638c29 2578
toddouska 0:5045d2638c29 2579 /* alias for dest */
toddouska 0:5045d2638c29 2580 tmpb = b->dp;
toddouska 0:5045d2638c29 2581
toddouska 0:5045d2638c29 2582 /* carry */
toddouska 0:5045d2638c29 2583 r = 0;
toddouska 0:5045d2638c29 2584 for (x = 0; x < a->used; x++) {
toddouska 0:5045d2638c29 2585
toddouska 0:5045d2638c29 2586 /* get what will be the *next* carry bit from the
toddouska 0:5045d2638c29 2587 * MSB of the current digit
toddouska 0:5045d2638c29 2588 */
toddouska 0:5045d2638c29 2589 rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
toddouska 0:5045d2638c29 2590
toddouska 0:5045d2638c29 2591 /* now shift up this digit, add in the carry [from the previous] */
toddouska 0:5045d2638c29 2592 *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
toddouska 0:5045d2638c29 2593
toddouska 0:5045d2638c29 2594 /* copy the carry that would be from the source
toddouska 0:5045d2638c29 2595 * digit into the next iteration
toddouska 0:5045d2638c29 2596 */
toddouska 0:5045d2638c29 2597 r = rr;
toddouska 0:5045d2638c29 2598 }
toddouska 0:5045d2638c29 2599
toddouska 0:5045d2638c29 2600 /* new leading digit? */
toddouska 0:5045d2638c29 2601 if (r != 0) {
toddouska 0:5045d2638c29 2602 /* add a MSB which is always 1 at this point */
toddouska 0:5045d2638c29 2603 *tmpb = 1;
toddouska 0:5045d2638c29 2604 ++(b->used);
toddouska 0:5045d2638c29 2605 }
toddouska 0:5045d2638c29 2606
toddouska 0:5045d2638c29 2607 /* now zero any excess digits on the destination
toddouska 0:5045d2638c29 2608 * that we didn't write to
toddouska 0:5045d2638c29 2609 */
toddouska 0:5045d2638c29 2610 tmpb = b->dp + b->used;
toddouska 0:5045d2638c29 2611 for (x = b->used; x < oldused; x++) {
toddouska 0:5045d2638c29 2612 *tmpb++ = 0;
toddouska 0:5045d2638c29 2613 }
toddouska 0:5045d2638c29 2614 }
toddouska 0:5045d2638c29 2615 b->sign = a->sign;
toddouska 0:5045d2638c29 2616 return MP_OKAY;
toddouska 0:5045d2638c29 2617 }
toddouska 0:5045d2638c29 2618
toddouska 0:5045d2638c29 2619
toddouska 0:5045d2638c29 2620 /* divide by three (based on routine from MPI and the GMP manual) */
toddouska 0:5045d2638c29 2621 int
toddouska 0:5045d2638c29 2622 mp_div_3 (mp_int * a, mp_int *c, mp_digit * d)
toddouska 0:5045d2638c29 2623 {
toddouska 0:5045d2638c29 2624 mp_int q;
toddouska 0:5045d2638c29 2625 mp_word w, t;
toddouska 0:5045d2638c29 2626 mp_digit b;
toddouska 0:5045d2638c29 2627 int res, ix;
toddouska 0:5045d2638c29 2628
toddouska 0:5045d2638c29 2629 /* b = 2**DIGIT_BIT / 3 */
toddouska 0:5045d2638c29 2630 b = (((mp_word)1) << ((mp_word)DIGIT_BIT)) / ((mp_word)3);
toddouska 0:5045d2638c29 2631
toddouska 0:5045d2638c29 2632 if ((res = mp_init_size(&q, a->used)) != MP_OKAY) {
toddouska 0:5045d2638c29 2633 return res;
toddouska 0:5045d2638c29 2634 }
toddouska 0:5045d2638c29 2635
toddouska 0:5045d2638c29 2636 q.used = a->used;
toddouska 0:5045d2638c29 2637 q.sign = a->sign;
toddouska 0:5045d2638c29 2638 w = 0;
toddouska 0:5045d2638c29 2639 for (ix = a->used - 1; ix >= 0; ix--) {
toddouska 0:5045d2638c29 2640 w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]);
toddouska 0:5045d2638c29 2641
toddouska 0:5045d2638c29 2642 if (w >= 3) {
toddouska 0:5045d2638c29 2643 /* multiply w by [1/3] */
toddouska 0:5045d2638c29 2644 t = (w * ((mp_word)b)) >> ((mp_word)DIGIT_BIT);
toddouska 0:5045d2638c29 2645
toddouska 0:5045d2638c29 2646 /* now subtract 3 * [w/3] from w, to get the remainder */
toddouska 0:5045d2638c29 2647 w -= t+t+t;
toddouska 0:5045d2638c29 2648
toddouska 0:5045d2638c29 2649 /* fixup the remainder as required since
toddouska 0:5045d2638c29 2650 * the optimization is not exact.
toddouska 0:5045d2638c29 2651 */
toddouska 0:5045d2638c29 2652 while (w >= 3) {
toddouska 0:5045d2638c29 2653 t += 1;
toddouska 0:5045d2638c29 2654 w -= 3;
toddouska 0:5045d2638c29 2655 }
toddouska 0:5045d2638c29 2656 } else {
toddouska 0:5045d2638c29 2657 t = 0;
toddouska 0:5045d2638c29 2658 }
toddouska 0:5045d2638c29 2659 q.dp[ix] = (mp_digit)t;
toddouska 0:5045d2638c29 2660 }
toddouska 0:5045d2638c29 2661
toddouska 0:5045d2638c29 2662 /* [optional] store the remainder */
toddouska 0:5045d2638c29 2663 if (d != NULL) {
toddouska 0:5045d2638c29 2664 *d = (mp_digit)w;
toddouska 0:5045d2638c29 2665 }
toddouska 0:5045d2638c29 2666
toddouska 0:5045d2638c29 2667 /* [optional] store the quotient */
toddouska 0:5045d2638c29 2668 if (c != NULL) {
toddouska 0:5045d2638c29 2669 mp_clamp(&q);
toddouska 0:5045d2638c29 2670 mp_exch(&q, c);
toddouska 0:5045d2638c29 2671 }
toddouska 0:5045d2638c29 2672 mp_clear(&q);
toddouska 0:5045d2638c29 2673
toddouska 0:5045d2638c29 2674 return res;
toddouska 0:5045d2638c29 2675 }
toddouska 0:5045d2638c29 2676
toddouska 0:5045d2638c29 2677
toddouska 0:5045d2638c29 2678 /* init an mp_init for a given size */
toddouska 0:5045d2638c29 2679 int mp_init_size (mp_int * a, int size)
toddouska 0:5045d2638c29 2680 {
toddouska 0:5045d2638c29 2681 int x;
toddouska 0:5045d2638c29 2682
toddouska 0:5045d2638c29 2683 /* pad size so there are always extra digits */
toddouska 0:5045d2638c29 2684 size += (MP_PREC * 2) - (size % MP_PREC);
toddouska 0:5045d2638c29 2685
toddouska 0:5045d2638c29 2686 /* alloc mem */
toddouska 0:5045d2638c29 2687 a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size, 0,
toddouska 0:5045d2638c29 2688 DYNAMIC_TYPE_BIGINT);
toddouska 0:5045d2638c29 2689 if (a->dp == NULL) {
toddouska 0:5045d2638c29 2690 return MP_MEM;
toddouska 0:5045d2638c29 2691 }
toddouska 0:5045d2638c29 2692
toddouska 0:5045d2638c29 2693 /* set the members */
toddouska 0:5045d2638c29 2694 a->used = 0;
toddouska 0:5045d2638c29 2695 a->alloc = size;
toddouska 0:5045d2638c29 2696 a->sign = MP_ZPOS;
toddouska 0:5045d2638c29 2697
toddouska 0:5045d2638c29 2698 /* zero the digits */
toddouska 0:5045d2638c29 2699 for (x = 0; x < size; x++) {
toddouska 0:5045d2638c29 2700 a->dp[x] = 0;
toddouska 0:5045d2638c29 2701 }
toddouska 0:5045d2638c29 2702
toddouska 0:5045d2638c29 2703 return MP_OKAY;
toddouska 0:5045d2638c29 2704 }
toddouska 0:5045d2638c29 2705
toddouska 0:5045d2638c29 2706
toddouska 0:5045d2638c29 2707 /* the jist of squaring...
toddouska 0:5045d2638c29 2708 * you do like mult except the offset of the tmpx [one that
toddouska 0:5045d2638c29 2709 * starts closer to zero] can't equal the offset of tmpy.
toddouska 0:5045d2638c29 2710 * So basically you set up iy like before then you min it with
toddouska 0:5045d2638c29 2711 * (ty-tx) so that it never happens. You double all those
toddouska 0:5045d2638c29 2712 * you add in the inner loop
toddouska 0:5045d2638c29 2713
toddouska 0:5045d2638c29 2714 After that loop you do the squares and add them in.
toddouska 0:5045d2638c29 2715 */
toddouska 0:5045d2638c29 2716
toddouska 0:5045d2638c29 2717 int fast_s_mp_sqr (mp_int * a, mp_int * b)
toddouska 0:5045d2638c29 2718 {
toddouska 0:5045d2638c29 2719 int olduse, res, pa, ix, iz;
toddouska 0:5045d2638c29 2720 mp_digit W[MP_WARRAY], *tmpx;
toddouska 0:5045d2638c29 2721 mp_word W1;
toddouska 0:5045d2638c29 2722
toddouska 0:5045d2638c29 2723 /* grow the destination as required */
toddouska 0:5045d2638c29 2724 pa = a->used + a->used;
toddouska 0:5045d2638c29 2725 if (b->alloc < pa) {
toddouska 0:5045d2638c29 2726 if ((res = mp_grow (b, pa)) != MP_OKAY) {
toddouska 0:5045d2638c29 2727 return res;
toddouska 0:5045d2638c29 2728 }
toddouska 0:5045d2638c29 2729 }
toddouska 0:5045d2638c29 2730
toddouska 0:5045d2638c29 2731 /* number of output digits to produce */
toddouska 0:5045d2638c29 2732 W1 = 0;
toddouska 0:5045d2638c29 2733 for (ix = 0; ix < pa; ix++) {
toddouska 0:5045d2638c29 2734 int tx, ty, iy;
toddouska 0:5045d2638c29 2735 mp_word _W;
toddouska 0:5045d2638c29 2736 mp_digit *tmpy;
toddouska 0:5045d2638c29 2737
toddouska 0:5045d2638c29 2738 /* clear counter */
toddouska 0:5045d2638c29 2739 _W = 0;
toddouska 0:5045d2638c29 2740
toddouska 0:5045d2638c29 2741 /* get offsets into the two bignums */
toddouska 0:5045d2638c29 2742 ty = MIN(a->used-1, ix);
toddouska 0:5045d2638c29 2743 tx = ix - ty;
toddouska 0:5045d2638c29 2744
toddouska 0:5045d2638c29 2745 /* setup temp aliases */
toddouska 0:5045d2638c29 2746 tmpx = a->dp + tx;
toddouska 0:5045d2638c29 2747 tmpy = a->dp + ty;
toddouska 0:5045d2638c29 2748
toddouska 0:5045d2638c29 2749 /* this is the number of times the loop will iterrate, essentially
toddouska 0:5045d2638c29 2750 while (tx++ < a->used && ty-- >= 0) { ... }
toddouska 0:5045d2638c29 2751 */
toddouska 0:5045d2638c29 2752 iy = MIN(a->used-tx, ty+1);
toddouska 0:5045d2638c29 2753
toddouska 0:5045d2638c29 2754 /* now for squaring tx can never equal ty
toddouska 0:5045d2638c29 2755 * we halve the distance since they approach at a rate of 2x
toddouska 0:5045d2638c29 2756 * and we have to round because odd cases need to be executed
toddouska 0:5045d2638c29 2757 */
toddouska 0:5045d2638c29 2758 iy = MIN(iy, (ty-tx+1)>>1);
toddouska 0:5045d2638c29 2759
toddouska 0:5045d2638c29 2760 /* execute loop */
toddouska 0:5045d2638c29 2761 for (iz = 0; iz < iy; iz++) {
toddouska 0:5045d2638c29 2762 _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
toddouska 0:5045d2638c29 2763 }
toddouska 0:5045d2638c29 2764
toddouska 0:5045d2638c29 2765 /* double the inner product and add carry */
toddouska 0:5045d2638c29 2766 _W = _W + _W + W1;
toddouska 0:5045d2638c29 2767
toddouska 0:5045d2638c29 2768 /* even columns have the square term in them */
toddouska 0:5045d2638c29 2769 if ((ix&1) == 0) {
toddouska 0:5045d2638c29 2770 _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
toddouska 0:5045d2638c29 2771 }
toddouska 0:5045d2638c29 2772
toddouska 0:5045d2638c29 2773 /* store it */
toddouska 0:5045d2638c29 2774 W[ix] = (mp_digit)(_W & MP_MASK);
toddouska 0:5045d2638c29 2775
toddouska 0:5045d2638c29 2776 /* make next carry */
toddouska 0:5045d2638c29 2777 W1 = _W >> ((mp_word)DIGIT_BIT);
toddouska 0:5045d2638c29 2778 }
toddouska 0:5045d2638c29 2779
toddouska 0:5045d2638c29 2780 /* setup dest */
toddouska 0:5045d2638c29 2781 olduse = b->used;
toddouska 0:5045d2638c29 2782 b->used = a->used+a->used;
toddouska 0:5045d2638c29 2783
toddouska 0:5045d2638c29 2784 {
toddouska 0:5045d2638c29 2785 mp_digit *tmpb;
toddouska 0:5045d2638c29 2786 tmpb = b->dp;
toddouska 0:5045d2638c29 2787 for (ix = 0; ix < pa; ix++) {
toddouska 0:5045d2638c29 2788 *tmpb++ = W[ix] & MP_MASK;
toddouska 0:5045d2638c29 2789 }
toddouska 0:5045d2638c29 2790
toddouska 0:5045d2638c29 2791 /* clear unused digits [that existed in the old copy of c] */
toddouska 0:5045d2638c29 2792 for (; ix < olduse; ix++) {
toddouska 0:5045d2638c29 2793 *tmpb++ = 0;
toddouska 0:5045d2638c29 2794 }
toddouska 0:5045d2638c29 2795 }
toddouska 0:5045d2638c29 2796 mp_clamp (b);
toddouska 0:5045d2638c29 2797 return MP_OKAY;
toddouska 0:5045d2638c29 2798 }
toddouska 0:5045d2638c29 2799
toddouska 0:5045d2638c29 2800
toddouska 0:5045d2638c29 2801 /* Fast (comba) multiplier
toddouska 0:5045d2638c29 2802 *
toddouska 0:5045d2638c29 2803 * This is the fast column-array [comba] multiplier. It is
toddouska 0:5045d2638c29 2804 * designed to compute the columns of the product first
toddouska 0:5045d2638c29 2805 * then handle the carries afterwards. This has the effect
toddouska 0:5045d2638c29 2806 * of making the nested loops that compute the columns very
toddouska 0:5045d2638c29 2807 * simple and schedulable on super-scalar processors.
toddouska 0:5045d2638c29 2808 *
toddouska 0:5045d2638c29 2809 * This has been modified to produce a variable number of
toddouska 0:5045d2638c29 2810 * digits of output so if say only a half-product is required
toddouska 0:5045d2638c29 2811 * you don't have to compute the upper half (a feature
toddouska 0:5045d2638c29 2812 * required for fast Barrett reduction).
toddouska 0:5045d2638c29 2813 *
toddouska 0:5045d2638c29 2814 * Based on Algorithm 14.12 on pp.595 of HAC.
toddouska 0:5045d2638c29 2815 *
toddouska 0:5045d2638c29 2816 */
toddouska 0:5045d2638c29 2817 int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
toddouska 0:5045d2638c29 2818 {
toddouska 0:5045d2638c29 2819 int olduse, res, pa, ix, iz;
toddouska 0:5045d2638c29 2820 mp_digit W[MP_WARRAY];
toddouska 0:5045d2638c29 2821 register mp_word _W;
toddouska 0:5045d2638c29 2822
toddouska 0:5045d2638c29 2823 /* grow the destination as required */
toddouska 0:5045d2638c29 2824 if (c->alloc < digs) {
toddouska 0:5045d2638c29 2825 if ((res = mp_grow (c, digs)) != MP_OKAY) {
toddouska 0:5045d2638c29 2826 return res;
toddouska 0:5045d2638c29 2827 }
toddouska 0:5045d2638c29 2828 }
toddouska 0:5045d2638c29 2829
toddouska 0:5045d2638c29 2830 /* number of output digits to produce */
toddouska 0:5045d2638c29 2831 pa = MIN(digs, a->used + b->used);
toddouska 0:5045d2638c29 2832
toddouska 0:5045d2638c29 2833 /* clear the carry */
toddouska 0:5045d2638c29 2834 _W = 0;
toddouska 0:5045d2638c29 2835 for (ix = 0; ix < pa; ix++) {
toddouska 0:5045d2638c29 2836 int tx, ty;
toddouska 0:5045d2638c29 2837 int iy;
toddouska 0:5045d2638c29 2838 mp_digit *tmpx, *tmpy;
toddouska 0:5045d2638c29 2839
toddouska 0:5045d2638c29 2840 /* get offsets into the two bignums */
toddouska 0:5045d2638c29 2841 ty = MIN(b->used-1, ix);
toddouska 0:5045d2638c29 2842 tx = ix - ty;
toddouska 0:5045d2638c29 2843
toddouska 0:5045d2638c29 2844 /* setup temp aliases */
toddouska 0:5045d2638c29 2845 tmpx = a->dp + tx;
toddouska 0:5045d2638c29 2846 tmpy = b->dp + ty;
toddouska 0:5045d2638c29 2847
toddouska 0:5045d2638c29 2848 /* this is the number of times the loop will iterrate, essentially
toddouska 0:5045d2638c29 2849 while (tx++ < a->used && ty-- >= 0) { ... }
toddouska 0:5045d2638c29 2850 */
toddouska 0:5045d2638c29 2851 iy = MIN(a->used-tx, ty+1);
toddouska 0:5045d2638c29 2852
toddouska 0:5045d2638c29 2853 /* execute loop */
toddouska 0:5045d2638c29 2854 for (iz = 0; iz < iy; ++iz) {
toddouska 0:5045d2638c29 2855 _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
toddouska 0:5045d2638c29 2856
toddouska 0:5045d2638c29 2857 }
toddouska 0:5045d2638c29 2858
toddouska 0:5045d2638c29 2859 /* store term */
toddouska 0:5045d2638c29 2860 W[ix] = ((mp_digit)_W) & MP_MASK;
toddouska 0:5045d2638c29 2861
toddouska 0:5045d2638c29 2862 /* make next carry */
toddouska 0:5045d2638c29 2863 _W = _W >> ((mp_word)DIGIT_BIT);
toddouska 0:5045d2638c29 2864 }
toddouska 0:5045d2638c29 2865
toddouska 0:5045d2638c29 2866 /* setup dest */
toddouska 0:5045d2638c29 2867 olduse = c->used;
toddouska 0:5045d2638c29 2868 c->used = pa;
toddouska 0:5045d2638c29 2869
toddouska 0:5045d2638c29 2870 {
toddouska 0:5045d2638c29 2871 register mp_digit *tmpc;
toddouska 0:5045d2638c29 2872 tmpc = c->dp;
toddouska 0:5045d2638c29 2873 for (ix = 0; ix < pa+1; ix++) {
toddouska 0:5045d2638c29 2874 /* now extract the previous digit [below the carry] */
toddouska 0:5045d2638c29 2875 *tmpc++ = W[ix];
toddouska 0:5045d2638c29 2876 }
toddouska 0:5045d2638c29 2877
toddouska 0:5045d2638c29 2878 /* clear unused digits [that existed in the old copy of c] */
toddouska 0:5045d2638c29 2879 for (; ix < olduse; ix++) {
toddouska 0:5045d2638c29 2880 *tmpc++ = 0;
toddouska 0:5045d2638c29 2881 }
toddouska 0:5045d2638c29 2882 }
toddouska 0:5045d2638c29 2883 mp_clamp (c);
toddouska 0:5045d2638c29 2884 return MP_OKAY;
toddouska 0:5045d2638c29 2885 }
toddouska 0:5045d2638c29 2886
toddouska 0:5045d2638c29 2887
toddouska 0:5045d2638c29 2888 /* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
toddouska 0:5045d2638c29 2889 int s_mp_sqr (mp_int * a, mp_int * b)
toddouska 0:5045d2638c29 2890 {
toddouska 0:5045d2638c29 2891 mp_int t;
toddouska 0:5045d2638c29 2892 int res, ix, iy, pa;
toddouska 0:5045d2638c29 2893 mp_word r;
toddouska 0:5045d2638c29 2894 mp_digit u, tmpx, *tmpt;
toddouska 0:5045d2638c29 2895
toddouska 0:5045d2638c29 2896 pa = a->used;
toddouska 0:5045d2638c29 2897 if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) {
toddouska 0:5045d2638c29 2898 return res;
toddouska 0:5045d2638c29 2899 }
toddouska 0:5045d2638c29 2900
toddouska 0:5045d2638c29 2901 /* default used is maximum possible size */
toddouska 0:5045d2638c29 2902 t.used = 2*pa + 1;
toddouska 0:5045d2638c29 2903
toddouska 0:5045d2638c29 2904 for (ix = 0; ix < pa; ix++) {
toddouska 0:5045d2638c29 2905 /* first calculate the digit at 2*ix */
toddouska 0:5045d2638c29 2906 /* calculate double precision result */
toddouska 0:5045d2638c29 2907 r = ((mp_word) t.dp[2*ix]) +
toddouska 0:5045d2638c29 2908 ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]);
toddouska 0:5045d2638c29 2909
toddouska 0:5045d2638c29 2910 /* store lower part in result */
toddouska 0:5045d2638c29 2911 t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK));
toddouska 0:5045d2638c29 2912
toddouska 0:5045d2638c29 2913 /* get the carry */
toddouska 0:5045d2638c29 2914 u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
toddouska 0:5045d2638c29 2915
toddouska 0:5045d2638c29 2916 /* left hand side of A[ix] * A[iy] */
toddouska 0:5045d2638c29 2917 tmpx = a->dp[ix];
toddouska 0:5045d2638c29 2918
toddouska 0:5045d2638c29 2919 /* alias for where to store the results */
toddouska 0:5045d2638c29 2920 tmpt = t.dp + (2*ix + 1);
toddouska 0:5045d2638c29 2921
toddouska 0:5045d2638c29 2922 for (iy = ix + 1; iy < pa; iy++) {
toddouska 0:5045d2638c29 2923 /* first calculate the product */
toddouska 0:5045d2638c29 2924 r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
toddouska 0:5045d2638c29 2925
toddouska 0:5045d2638c29 2926 /* now calculate the double precision result, note we use
toddouska 0:5045d2638c29 2927 * addition instead of *2 since it's easier to optimize
toddouska 0:5045d2638c29 2928 */
toddouska 0:5045d2638c29 2929 r = ((mp_word) *tmpt) + r + r + ((mp_word) u);
toddouska 0:5045d2638c29 2930
toddouska 0:5045d2638c29 2931 /* store lower part */
toddouska 0:5045d2638c29 2932 *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
toddouska 0:5045d2638c29 2933
toddouska 0:5045d2638c29 2934 /* get carry */
toddouska 0:5045d2638c29 2935 u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
toddouska 0:5045d2638c29 2936 }
toddouska 0:5045d2638c29 2937 /* propagate upwards */
toddouska 0:5045d2638c29 2938 while (u != ((mp_digit) 0)) {
toddouska 0:5045d2638c29 2939 r = ((mp_word) *tmpt) + ((mp_word) u);
toddouska 0:5045d2638c29 2940 *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
toddouska 0:5045d2638c29 2941 u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
toddouska 0:5045d2638c29 2942 }
toddouska 0:5045d2638c29 2943 }
toddouska 0:5045d2638c29 2944
toddouska 0:5045d2638c29 2945 mp_clamp (&t);
toddouska 0:5045d2638c29 2946 mp_exch (&t, b);
toddouska 0:5045d2638c29 2947 mp_clear (&t);
toddouska 0:5045d2638c29 2948 return MP_OKAY;
toddouska 0:5045d2638c29 2949 }
toddouska 0:5045d2638c29 2950
toddouska 0:5045d2638c29 2951
toddouska 0:5045d2638c29 2952 /* multiplies |a| * |b| and only computes upto digs digits of result
toddouska 0:5045d2638c29 2953 * HAC pp. 595, Algorithm 14.12 Modified so you can control how
toddouska 0:5045d2638c29 2954 * many digits of output are created.
toddouska 0:5045d2638c29 2955 */
toddouska 0:5045d2638c29 2956 int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
toddouska 0:5045d2638c29 2957 {
toddouska 0:5045d2638c29 2958 mp_int t;
toddouska 0:5045d2638c29 2959 int res, pa, pb, ix, iy;
toddouska 0:5045d2638c29 2960 mp_digit u;
toddouska 0:5045d2638c29 2961 mp_word r;
toddouska 0:5045d2638c29 2962 mp_digit tmpx, *tmpt, *tmpy;
toddouska 0:5045d2638c29 2963
toddouska 0:5045d2638c29 2964 /* can we use the fast multiplier? */
toddouska 0:5045d2638c29 2965 if (((digs) < MP_WARRAY) &&
toddouska 0:5045d2638c29 2966 MIN (a->used, b->used) <
toddouska 0:5045d2638c29 2967 (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
toddouska 0:5045d2638c29 2968 return fast_s_mp_mul_digs (a, b, c, digs);
toddouska 0:5045d2638c29 2969 }
toddouska 0:5045d2638c29 2970
toddouska 0:5045d2638c29 2971 if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
toddouska 0:5045d2638c29 2972 return res;
toddouska 0:5045d2638c29 2973 }
toddouska 0:5045d2638c29 2974 t.used = digs;
toddouska 0:5045d2638c29 2975
toddouska 0:5045d2638c29 2976 /* compute the digits of the product directly */
toddouska 0:5045d2638c29 2977 pa = a->used;
toddouska 0:5045d2638c29 2978 for (ix = 0; ix < pa; ix++) {
toddouska 0:5045d2638c29 2979 /* set the carry to zero */
toddouska 0:5045d2638c29 2980 u = 0;
toddouska 0:5045d2638c29 2981
toddouska 0:5045d2638c29 2982 /* limit ourselves to making digs digits of output */
toddouska 0:5045d2638c29 2983 pb = MIN (b->used, digs - ix);
toddouska 0:5045d2638c29 2984
toddouska 0:5045d2638c29 2985 /* setup some aliases */
toddouska 0:5045d2638c29 2986 /* copy of the digit from a used within the nested loop */
toddouska 0:5045d2638c29 2987 tmpx = a->dp[ix];
toddouska 0:5045d2638c29 2988
toddouska 0:5045d2638c29 2989 /* an alias for the destination shifted ix places */
toddouska 0:5045d2638c29 2990 tmpt = t.dp + ix;
toddouska 0:5045d2638c29 2991
toddouska 0:5045d2638c29 2992 /* an alias for the digits of b */
toddouska 0:5045d2638c29 2993 tmpy = b->dp;
toddouska 0:5045d2638c29 2994
toddouska 0:5045d2638c29 2995 /* compute the columns of the output and propagate the carry */
toddouska 0:5045d2638c29 2996 for (iy = 0; iy < pb; iy++) {
toddouska 0:5045d2638c29 2997 /* compute the column as a mp_word */
toddouska 0:5045d2638c29 2998 r = ((mp_word)*tmpt) +
toddouska 0:5045d2638c29 2999 ((mp_word)tmpx) * ((mp_word)*tmpy++) +
toddouska 0:5045d2638c29 3000 ((mp_word) u);
toddouska 0:5045d2638c29 3001
toddouska 0:5045d2638c29 3002 /* the new column is the lower part of the result */
toddouska 0:5045d2638c29 3003 *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
toddouska 0:5045d2638c29 3004
toddouska 0:5045d2638c29 3005 /* get the carry word from the result */
toddouska 0:5045d2638c29 3006 u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
toddouska 0:5045d2638c29 3007 }
toddouska 0:5045d2638c29 3008 /* set carry if it is placed below digs */
toddouska 0:5045d2638c29 3009 if (ix + iy < digs) {
toddouska 0:5045d2638c29 3010 *tmpt = u;
toddouska 0:5045d2638c29 3011 }
toddouska 0:5045d2638c29 3012 }
toddouska 0:5045d2638c29 3013
toddouska 0:5045d2638c29 3014 mp_clamp (&t);
toddouska 0:5045d2638c29 3015 mp_exch (&t, c);
toddouska 0:5045d2638c29 3016
toddouska 0:5045d2638c29 3017 mp_clear (&t);
toddouska 0:5045d2638c29 3018 return MP_OKAY;
toddouska 0:5045d2638c29 3019 }
toddouska 0:5045d2638c29 3020
toddouska 0:5045d2638c29 3021
toddouska 0:5045d2638c29 3022 /*
toddouska 0:5045d2638c29 3023 * shifts with subtractions when the result is greater than b.
toddouska 0:5045d2638c29 3024 *
toddouska 0:5045d2638c29 3025 * The method is slightly modified to shift B unconditionally upto just under
toddouska 0:5045d2638c29 3026 * the leading bit of b. This saves alot of multiple precision shifting.
toddouska 0:5045d2638c29 3027 */
toddouska 0:5045d2638c29 3028 int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
toddouska 0:5045d2638c29 3029 {
toddouska 0:5045d2638c29 3030 int x, bits, res;
toddouska 0:5045d2638c29 3031
toddouska 0:5045d2638c29 3032 /* how many bits of last digit does b use */
toddouska 0:5045d2638c29 3033 bits = mp_count_bits (b) % DIGIT_BIT;
toddouska 0:5045d2638c29 3034
toddouska 0:5045d2638c29 3035 if (b->used > 1) {
toddouska 0:5045d2638c29 3036 if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) {
toddouska 0:5045d2638c29 3037 return res;
toddouska 0:5045d2638c29 3038 }
toddouska 0:5045d2638c29 3039 } else {
toddouska 0:5045d2638c29 3040 mp_set(a, 1);
toddouska 0:5045d2638c29 3041 bits = 1;
toddouska 0:5045d2638c29 3042 }
toddouska 0:5045d2638c29 3043
toddouska 0:5045d2638c29 3044
toddouska 0:5045d2638c29 3045 /* now compute C = A * B mod b */
toddouska 0:5045d2638c29 3046 for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
toddouska 0:5045d2638c29 3047 if ((res = mp_mul_2 (a, a)) != MP_OKAY) {
toddouska 0:5045d2638c29 3048 return res;
toddouska 0:5045d2638c29 3049 }
toddouska 0:5045d2638c29 3050 if (mp_cmp_mag (a, b) != MP_LT) {
toddouska 0:5045d2638c29 3051 if ((res = s_mp_sub (a, b, a)) != MP_OKAY) {
toddouska 0:5045d2638c29 3052 return res;
toddouska 0:5045d2638c29 3053 }
toddouska 0:5045d2638c29 3054 }
toddouska 0:5045d2638c29 3055 }
toddouska 0:5045d2638c29 3056
toddouska 0:5045d2638c29 3057 return MP_OKAY;
toddouska 0:5045d2638c29 3058 }
toddouska 0:5045d2638c29 3059
toddouska 0:5045d2638c29 3060
toddouska 0:5045d2638c29 3061 #ifdef MP_LOW_MEM
toddouska 0:5045d2638c29 3062 #define TAB_SIZE 32
toddouska 0:5045d2638c29 3063 #else
toddouska 0:5045d2638c29 3064 #define TAB_SIZE 256
toddouska 0:5045d2638c29 3065 #endif
toddouska 0:5045d2638c29 3066
toddouska 0:5045d2638c29 3067 int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
toddouska 0:5045d2638c29 3068 {
toddouska 0:5045d2638c29 3069 mp_int M[TAB_SIZE], res, mu;
toddouska 0:5045d2638c29 3070 mp_digit buf;
toddouska 0:5045d2638c29 3071 int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
toddouska 0:5045d2638c29 3072 int (*redux)(mp_int*,mp_int*,mp_int*);
toddouska 0:5045d2638c29 3073
toddouska 0:5045d2638c29 3074 /* find window size */
toddouska 0:5045d2638c29 3075 x = mp_count_bits (X);
toddouska 0:5045d2638c29 3076 if (x <= 7) {
toddouska 0:5045d2638c29 3077 winsize = 2;
toddouska 0:5045d2638c29 3078 } else if (x <= 36) {
toddouska 0:5045d2638c29 3079 winsize = 3;
toddouska 0:5045d2638c29 3080 } else if (x <= 140) {
toddouska 0:5045d2638c29 3081 winsize = 4;
toddouska 0:5045d2638c29 3082 } else if (x <= 450) {
toddouska 0:5045d2638c29 3083 winsize = 5;
toddouska 0:5045d2638c29 3084 } else if (x <= 1303) {
toddouska 0:5045d2638c29 3085 winsize = 6;
toddouska 0:5045d2638c29 3086 } else if (x <= 3529) {
toddouska 0:5045d2638c29 3087 winsize = 7;
toddouska 0:5045d2638c29 3088 } else {
toddouska 0:5045d2638c29 3089 winsize = 8;
toddouska 0:5045d2638c29 3090 }
toddouska 0:5045d2638c29 3091
toddouska 0:5045d2638c29 3092 #ifdef MP_LOW_MEM
toddouska 0:5045d2638c29 3093 if (winsize > 5) {
toddouska 0:5045d2638c29 3094 winsize = 5;
toddouska 0:5045d2638c29 3095 }
toddouska 0:5045d2638c29 3096 #endif
toddouska 0:5045d2638c29 3097
toddouska 0:5045d2638c29 3098 /* init M array */
toddouska 0:5045d2638c29 3099 /* init first cell */
toddouska 0:5045d2638c29 3100 if ((err = mp_init(&M[1])) != MP_OKAY) {
toddouska 0:5045d2638c29 3101 return err;
toddouska 0:5045d2638c29 3102 }
toddouska 0:5045d2638c29 3103
toddouska 0:5045d2638c29 3104 /* now init the second half of the array */
toddouska 0:5045d2638c29 3105 for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
toddouska 0:5045d2638c29 3106 if ((err = mp_init(&M[x])) != MP_OKAY) {
toddouska 0:5045d2638c29 3107 for (y = 1<<(winsize-1); y < x; y++) {
toddouska 0:5045d2638c29 3108 mp_clear (&M[y]);
toddouska 0:5045d2638c29 3109 }
toddouska 0:5045d2638c29 3110 mp_clear(&M[1]);
toddouska 0:5045d2638c29 3111 return err;
toddouska 0:5045d2638c29 3112 }
toddouska 0:5045d2638c29 3113 }
toddouska 0:5045d2638c29 3114
toddouska 0:5045d2638c29 3115 /* create mu, used for Barrett reduction */
toddouska 0:5045d2638c29 3116 if ((err = mp_init (&mu)) != MP_OKAY) {
toddouska 0:5045d2638c29 3117 goto LBL_M;
toddouska 0:5045d2638c29 3118 }
toddouska 0:5045d2638c29 3119
toddouska 0:5045d2638c29 3120 if (redmode == 0) {
toddouska 0:5045d2638c29 3121 if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
toddouska 0:5045d2638c29 3122 goto LBL_MU;
toddouska 0:5045d2638c29 3123 }
toddouska 0:5045d2638c29 3124 redux = mp_reduce;
toddouska 0:5045d2638c29 3125 } else {
toddouska 0:5045d2638c29 3126 if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) {
toddouska 0:5045d2638c29 3127 goto LBL_MU;
toddouska 0:5045d2638c29 3128 }
toddouska 0:5045d2638c29 3129 redux = mp_reduce_2k_l;
toddouska 0:5045d2638c29 3130 }
toddouska 0:5045d2638c29 3131
toddouska 0:5045d2638c29 3132 /* create M table
toddouska 0:5045d2638c29 3133 *
toddouska 0:5045d2638c29 3134 * The M table contains powers of the base,
toddouska 0:5045d2638c29 3135 * e.g. M[x] = G**x mod P
toddouska 0:5045d2638c29 3136 *
toddouska 0:5045d2638c29 3137 * The first half of the table is not
toddouska 0:5045d2638c29 3138 * computed though accept for M[0] and M[1]
toddouska 0:5045d2638c29 3139 */
toddouska 0:5045d2638c29 3140 if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
toddouska 0:5045d2638c29 3141 goto LBL_MU;
toddouska 0:5045d2638c29 3142 }
toddouska 0:5045d2638c29 3143
toddouska 0:5045d2638c29 3144 /* compute the value at M[1<<(winsize-1)] by squaring
toddouska 0:5045d2638c29 3145 * M[1] (winsize-1) times
toddouska 0:5045d2638c29 3146 */
toddouska 0:5045d2638c29 3147 if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
toddouska 0:5045d2638c29 3148 goto LBL_MU;
toddouska 0:5045d2638c29 3149 }
toddouska 0:5045d2638c29 3150
toddouska 0:5045d2638c29 3151 for (x = 0; x < (winsize - 1); x++) {
toddouska 0:5045d2638c29 3152 /* square it */
toddouska 0:5045d2638c29 3153 if ((err = mp_sqr (&M[1 << (winsize - 1)],
toddouska 0:5045d2638c29 3154 &M[1 << (winsize - 1)])) != MP_OKAY) {
toddouska 0:5045d2638c29 3155 goto LBL_MU;
toddouska 0:5045d2638c29 3156 }
toddouska 0:5045d2638c29 3157
toddouska 0:5045d2638c29 3158 /* reduce modulo P */
toddouska 0:5045d2638c29 3159 if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) {
toddouska 0:5045d2638c29 3160 goto LBL_MU;
toddouska 0:5045d2638c29 3161 }
toddouska 0:5045d2638c29 3162 }
toddouska 0:5045d2638c29 3163
toddouska 0:5045d2638c29 3164 /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
toddouska 0:5045d2638c29 3165 * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
toddouska 0:5045d2638c29 3166 */
toddouska 0:5045d2638c29 3167 for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
toddouska 0:5045d2638c29 3168 if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
toddouska 0:5045d2638c29 3169 goto LBL_MU;
toddouska 0:5045d2638c29 3170 }
toddouska 0:5045d2638c29 3171 if ((err = redux (&M[x], P, &mu)) != MP_OKAY) {
toddouska 0:5045d2638c29 3172 goto LBL_MU;
toddouska 0:5045d2638c29 3173 }
toddouska 0:5045d2638c29 3174 }
toddouska 0:5045d2638c29 3175
toddouska 0:5045d2638c29 3176 /* setup result */
toddouska 0:5045d2638c29 3177 if ((err = mp_init (&res)) != MP_OKAY) {
toddouska 0:5045d2638c29 3178 goto LBL_MU;
toddouska 0:5045d2638c29 3179 }
toddouska 0:5045d2638c29 3180 mp_set (&res, 1);
toddouska 0:5045d2638c29 3181
toddouska 0:5045d2638c29 3182 /* set initial mode and bit cnt */
toddouska 0:5045d2638c29 3183 mode = 0;
toddouska 0:5045d2638c29 3184 bitcnt = 1;
toddouska 0:5045d2638c29 3185 buf = 0;
toddouska 0:5045d2638c29 3186 digidx = X->used - 1;
toddouska 0:5045d2638c29 3187 bitcpy = 0;
toddouska 0:5045d2638c29 3188 bitbuf = 0;
toddouska 0:5045d2638c29 3189
toddouska 0:5045d2638c29 3190 for (;;) {
toddouska 0:5045d2638c29 3191 /* grab next digit as required */
toddouska 0:5045d2638c29 3192 if (--bitcnt == 0) {
toddouska 0:5045d2638c29 3193 /* if digidx == -1 we are out of digits */
toddouska 0:5045d2638c29 3194 if (digidx == -1) {
toddouska 0:5045d2638c29 3195 break;
toddouska 0:5045d2638c29 3196 }
toddouska 0:5045d2638c29 3197 /* read next digit and reset the bitcnt */
toddouska 0:5045d2638c29 3198 buf = X->dp[digidx--];
toddouska 0:5045d2638c29 3199 bitcnt = (int) DIGIT_BIT;
toddouska 0:5045d2638c29 3200 }
toddouska 0:5045d2638c29 3201
toddouska 0:5045d2638c29 3202 /* grab the next msb from the exponent */
toddouska 0:5045d2638c29 3203 y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1;
toddouska 0:5045d2638c29 3204 buf <<= (mp_digit)1;
toddouska 0:5045d2638c29 3205
toddouska 0:5045d2638c29 3206 /* if the bit is zero and mode == 0 then we ignore it
toddouska 0:5045d2638c29 3207 * These represent the leading zero bits before the first 1 bit
toddouska 0:5045d2638c29 3208 * in the exponent. Technically this opt is not required but it
toddouska 0:5045d2638c29 3209 * does lower the # of trivial squaring/reductions used
toddouska 0:5045d2638c29 3210 */
toddouska 0:5045d2638c29 3211 if (mode == 0 && y == 0) {
toddouska 0:5045d2638c29 3212 continue;
toddouska 0:5045d2638c29 3213 }
toddouska 0:5045d2638c29 3214
toddouska 0:5045d2638c29 3215 /* if the bit is zero and mode == 1 then we square */
toddouska 0:5045d2638c29 3216 if (mode == 1 && y == 0) {
toddouska 0:5045d2638c29 3217 if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
toddouska 0:5045d2638c29 3218 goto LBL_RES;
toddouska 0:5045d2638c29 3219 }
toddouska 0:5045d2638c29 3220 if ((err = redux (&res, P, &mu)) != MP_OKAY) {
toddouska 0:5045d2638c29 3221 goto LBL_RES;
toddouska 0:5045d2638c29 3222 }
toddouska 0:5045d2638c29 3223 continue;
toddouska 0:5045d2638c29 3224 }
toddouska 0:5045d2638c29 3225
toddouska 0:5045d2638c29 3226 /* else we add it to the window */
toddouska 0:5045d2638c29 3227 bitbuf |= (y << (winsize - ++bitcpy));
toddouska 0:5045d2638c29 3228 mode = 2;
toddouska 0:5045d2638c29 3229
toddouska 0:5045d2638c29 3230 if (bitcpy == winsize) {
toddouska 0:5045d2638c29 3231 /* ok window is filled so square as required and multiply */
toddouska 0:5045d2638c29 3232 /* square first */
toddouska 0:5045d2638c29 3233 for (x = 0; x < winsize; x++) {
toddouska 0:5045d2638c29 3234 if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
toddouska 0:5045d2638c29 3235 goto LBL_RES;
toddouska 0:5045d2638c29 3236 }
toddouska 0:5045d2638c29 3237 if ((err = redux (&res, P, &mu)) != MP_OKAY) {
toddouska 0:5045d2638c29 3238 goto LBL_RES;
toddouska 0:5045d2638c29 3239 }
toddouska 0:5045d2638c29 3240 }
toddouska 0:5045d2638c29 3241
toddouska 0:5045d2638c29 3242 /* then multiply */
toddouska 0:5045d2638c29 3243 if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
toddouska 0:5045d2638c29 3244 goto LBL_RES;
toddouska 0:5045d2638c29 3245 }
toddouska 0:5045d2638c29 3246 if ((err = redux (&res, P, &mu)) != MP_OKAY) {
toddouska 0:5045d2638c29 3247 goto LBL_RES;
toddouska 0:5045d2638c29 3248 }
toddouska 0:5045d2638c29 3249
toddouska 0:5045d2638c29 3250 /* empty window and reset */
toddouska 0:5045d2638c29 3251 bitcpy = 0;
toddouska 0:5045d2638c29 3252 bitbuf = 0;
toddouska 0:5045d2638c29 3253 mode = 1;
toddouska 0:5045d2638c29 3254 }
toddouska 0:5045d2638c29 3255 }
toddouska 0:5045d2638c29 3256
toddouska 0:5045d2638c29 3257 /* if bits remain then square/multiply */
toddouska 0:5045d2638c29 3258 if (mode == 2 && bitcpy > 0) {
toddouska 0:5045d2638c29 3259 /* square then multiply if the bit is set */
toddouska 0:5045d2638c29 3260 for (x = 0; x < bitcpy; x++) {
toddouska 0:5045d2638c29 3261 if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
toddouska 0:5045d2638c29 3262 goto LBL_RES;
toddouska 0:5045d2638c29 3263 }
toddouska 0:5045d2638c29 3264 if ((err = redux (&res, P, &mu)) != MP_OKAY) {
toddouska 0:5045d2638c29 3265 goto LBL_RES;
toddouska 0:5045d2638c29 3266 }
toddouska 0:5045d2638c29 3267
toddouska 0:5045d2638c29 3268 bitbuf <<= 1;
toddouska 0:5045d2638c29 3269 if ((bitbuf & (1 << winsize)) != 0) {
toddouska 0:5045d2638c29 3270 /* then multiply */
toddouska 0:5045d2638c29 3271 if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
toddouska 0:5045d2638c29 3272 goto LBL_RES;
toddouska 0:5045d2638c29 3273 }
toddouska 0:5045d2638c29 3274 if ((err = redux (&res, P, &mu)) != MP_OKAY) {
toddouska 0:5045d2638c29 3275 goto LBL_RES;
toddouska 0:5045d2638c29 3276 }
toddouska 0:5045d2638c29 3277 }
toddouska 0:5045d2638c29 3278 }
toddouska 0:5045d2638c29 3279 }
toddouska 0:5045d2638c29 3280
toddouska 0:5045d2638c29 3281 mp_exch (&res, Y);
toddouska 0:5045d2638c29 3282 err = MP_OKAY;
toddouska 0:5045d2638c29 3283 LBL_RES:mp_clear (&res);
toddouska 0:5045d2638c29 3284 LBL_MU:mp_clear (&mu);
toddouska 0:5045d2638c29 3285 LBL_M:
toddouska 0:5045d2638c29 3286 mp_clear(&M[1]);
toddouska 0:5045d2638c29 3287 for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
toddouska 0:5045d2638c29 3288 mp_clear (&M[x]);
toddouska 0:5045d2638c29 3289 }
toddouska 0:5045d2638c29 3290 return err;
toddouska 0:5045d2638c29 3291 }
toddouska 0:5045d2638c29 3292
toddouska 0:5045d2638c29 3293
toddouska 0:5045d2638c29 3294 /* pre-calculate the value required for Barrett reduction
toddouska 0:5045d2638c29 3295 * For a given modulus "b" it calulates the value required in "a"
toddouska 0:5045d2638c29 3296 */
toddouska 0:5045d2638c29 3297 int mp_reduce_setup (mp_int * a, mp_int * b)
toddouska 0:5045d2638c29 3298 {
toddouska 0:5045d2638c29 3299 int res;
toddouska 0:5045d2638c29 3300
toddouska 0:5045d2638c29 3301 if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
toddouska 0:5045d2638c29 3302 return res;
toddouska 0:5045d2638c29 3303 }
toddouska 0:5045d2638c29 3304 return mp_div (a, b, a, NULL);
toddouska 0:5045d2638c29 3305 }
toddouska 0:5045d2638c29 3306
toddouska 0:5045d2638c29 3307
toddouska 0:5045d2638c29 3308 /* reduces x mod m, assumes 0 < x < m**2, mu is
toddouska 0:5045d2638c29 3309 * precomputed via mp_reduce_setup.
toddouska 0:5045d2638c29 3310 * From HAC pp.604 Algorithm 14.42
toddouska 0:5045d2638c29 3311 */
toddouska 0:5045d2638c29 3312 int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
toddouska 0:5045d2638c29 3313 {
toddouska 0:5045d2638c29 3314 mp_int q;
toddouska 0:5045d2638c29 3315 int res, um = m->used;
toddouska 0:5045d2638c29 3316
toddouska 0:5045d2638c29 3317 /* q = x */
toddouska 0:5045d2638c29 3318 if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
toddouska 0:5045d2638c29 3319 return res;
toddouska 0:5045d2638c29 3320 }
toddouska 0:5045d2638c29 3321
toddouska 0:5045d2638c29 3322 /* q1 = x / b**(k-1) */
toddouska 0:5045d2638c29 3323 mp_rshd (&q, um - 1);
toddouska 0:5045d2638c29 3324
toddouska 0:5045d2638c29 3325 /* according to HAC this optimization is ok */
toddouska 0:5045d2638c29 3326 if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
toddouska 0:5045d2638c29 3327 if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
toddouska 0:5045d2638c29 3328 goto CLEANUP;
toddouska 0:5045d2638c29 3329 }
toddouska 0:5045d2638c29 3330 } else {
toddouska 0:5045d2638c29 3331 #ifdef BN_S_MP_MUL_HIGH_DIGS_C
toddouska 0:5045d2638c29 3332 if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
toddouska 0:5045d2638c29 3333 goto CLEANUP;
toddouska 0:5045d2638c29 3334 }
toddouska 0:5045d2638c29 3335 #elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
toddouska 0:5045d2638c29 3336 if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
toddouska 0:5045d2638c29 3337 goto CLEANUP;
toddouska 0:5045d2638c29 3338 }
toddouska 0:5045d2638c29 3339 #else
toddouska 0:5045d2638c29 3340 {
toddouska 0:5045d2638c29 3341 res = MP_VAL;
toddouska 0:5045d2638c29 3342 goto CLEANUP;
toddouska 0:5045d2638c29 3343 }
toddouska 0:5045d2638c29 3344 #endif
toddouska 0:5045d2638c29 3345 }
toddouska 0:5045d2638c29 3346
toddouska 0:5045d2638c29 3347 /* q3 = q2 / b**(k+1) */
toddouska 0:5045d2638c29 3348 mp_rshd (&q, um + 1);
toddouska 0:5045d2638c29 3349
toddouska 0:5045d2638c29 3350 /* x = x mod b**(k+1), quick (no division) */
toddouska 0:5045d2638c29 3351 if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
toddouska 0:5045d2638c29 3352 goto CLEANUP;
toddouska 0:5045d2638c29 3353 }
toddouska 0:5045d2638c29 3354
toddouska 0:5045d2638c29 3355 /* q = q * m mod b**(k+1), quick (no division) */
toddouska 0:5045d2638c29 3356 if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
toddouska 0:5045d2638c29 3357 goto CLEANUP;
toddouska 0:5045d2638c29 3358 }
toddouska 0:5045d2638c29 3359
toddouska 0:5045d2638c29 3360 /* x = x - q */
toddouska 0:5045d2638c29 3361 if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
toddouska 0:5045d2638c29 3362 goto CLEANUP;
toddouska 0:5045d2638c29 3363 }
toddouska 0:5045d2638c29 3364
toddouska 0:5045d2638c29 3365 /* If x < 0, add b**(k+1) to it */
toddouska 0:5045d2638c29 3366 if (mp_cmp_d (x, 0) == MP_LT) {
toddouska 0:5045d2638c29 3367 mp_set (&q, 1);
toddouska 0:5045d2638c29 3368 if ((res = mp_lshd (&q, um + 1)) != MP_OKAY)
toddouska 0:5045d2638c29 3369 goto CLEANUP;
toddouska 0:5045d2638c29 3370 if ((res = mp_add (x, &q, x)) != MP_OKAY)
toddouska 0:5045d2638c29 3371 goto CLEANUP;
toddouska 0:5045d2638c29 3372 }
toddouska 0:5045d2638c29 3373
toddouska 0:5045d2638c29 3374 /* Back off if it's too big */
toddouska 0:5045d2638c29 3375 while (mp_cmp (x, m) != MP_LT) {
toddouska 0:5045d2638c29 3376 if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
toddouska 0:5045d2638c29 3377 goto CLEANUP;
toddouska 0:5045d2638c29 3378 }
toddouska 0:5045d2638c29 3379 }
toddouska 0:5045d2638c29 3380
toddouska 0:5045d2638c29 3381 CLEANUP:
toddouska 0:5045d2638c29 3382 mp_clear (&q);
toddouska 0:5045d2638c29 3383
toddouska 0:5045d2638c29 3384 return res;
toddouska 0:5045d2638c29 3385 }
toddouska 0:5045d2638c29 3386
toddouska 0:5045d2638c29 3387
toddouska 0:5045d2638c29 3388 /* reduces a modulo n where n is of the form 2**p - d
toddouska 0:5045d2638c29 3389 This differs from reduce_2k since "d" can be larger
toddouska 0:5045d2638c29 3390 than a single digit.
toddouska 0:5045d2638c29 3391 */
toddouska 0:5045d2638c29 3392 int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
toddouska 0:5045d2638c29 3393 {
toddouska 0:5045d2638c29 3394 mp_int q;
toddouska 0:5045d2638c29 3395 int p, res;
toddouska 0:5045d2638c29 3396
toddouska 0:5045d2638c29 3397 if ((res = mp_init(&q)) != MP_OKAY) {
toddouska 0:5045d2638c29 3398 return res;
toddouska 0:5045d2638c29 3399 }
toddouska 0:5045d2638c29 3400
toddouska 0:5045d2638c29 3401 p = mp_count_bits(n);
toddouska 0:5045d2638c29 3402 top:
toddouska 0:5045d2638c29 3403 /* q = a/2**p, a = a mod 2**p */
toddouska 0:5045d2638c29 3404 if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
toddouska 0:5045d2638c29 3405 goto ERR;
toddouska 0:5045d2638c29 3406 }
toddouska 0:5045d2638c29 3407
toddouska 0:5045d2638c29 3408 /* q = q * d */
toddouska 0:5045d2638c29 3409 if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
toddouska 0:5045d2638c29 3410 goto ERR;
toddouska 0:5045d2638c29 3411 }
toddouska 0:5045d2638c29 3412
toddouska 0:5045d2638c29 3413 /* a = a + q */
toddouska 0:5045d2638c29 3414 if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
toddouska 0:5045d2638c29 3415 goto ERR;
toddouska 0:5045d2638c29 3416 }
toddouska 0:5045d2638c29 3417
toddouska 0:5045d2638c29 3418 if (mp_cmp_mag(a, n) != MP_LT) {
toddouska 0:5045d2638c29 3419 s_mp_sub(a, n, a);
toddouska 0:5045d2638c29 3420 goto top;
toddouska 0:5045d2638c29 3421 }
toddouska 0:5045d2638c29 3422
toddouska 0:5045d2638c29 3423 ERR:
toddouska 0:5045d2638c29 3424 mp_clear(&q);
toddouska 0:5045d2638c29 3425 return res;
toddouska 0:5045d2638c29 3426 }
toddouska 0:5045d2638c29 3427
toddouska 0:5045d2638c29 3428
toddouska 0:5045d2638c29 3429 /* determines the setup value */
toddouska 0:5045d2638c29 3430 int mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
toddouska 0:5045d2638c29 3431 {
toddouska 0:5045d2638c29 3432 int res;
toddouska 0:5045d2638c29 3433 mp_int tmp;
toddouska 0:5045d2638c29 3434
toddouska 0:5045d2638c29 3435 if ((res = mp_init(&tmp)) != MP_OKAY) {
toddouska 0:5045d2638c29 3436 return res;
toddouska 0:5045d2638c29 3437 }
toddouska 0:5045d2638c29 3438
toddouska 0:5045d2638c29 3439 if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
toddouska 0:5045d2638c29 3440 goto ERR;
toddouska 0:5045d2638c29 3441 }
toddouska 0:5045d2638c29 3442
toddouska 0:5045d2638c29 3443 if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
toddouska 0:5045d2638c29 3444 goto ERR;
toddouska 0:5045d2638c29 3445 }
toddouska 0:5045d2638c29 3446
toddouska 0:5045d2638c29 3447 ERR:
toddouska 0:5045d2638c29 3448 mp_clear(&tmp);
toddouska 0:5045d2638c29 3449 return res;
toddouska 0:5045d2638c29 3450 }
toddouska 0:5045d2638c29 3451
toddouska 0:5045d2638c29 3452
toddouska 0:5045d2638c29 3453 /* multiplies |a| * |b| and does not compute the lower digs digits
toddouska 0:5045d2638c29 3454 * [meant to get the higher part of the product]
toddouska 0:5045d2638c29 3455 */
toddouska 0:5045d2638c29 3456 int
toddouska 0:5045d2638c29 3457 s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
toddouska 0:5045d2638c29 3458 {
toddouska 0:5045d2638c29 3459 mp_int t;
toddouska 0:5045d2638c29 3460 int res, pa, pb, ix, iy;
toddouska 0:5045d2638c29 3461 mp_digit u;
toddouska 0:5045d2638c29 3462 mp_word r;
toddouska 0:5045d2638c29 3463 mp_digit tmpx, *tmpt, *tmpy;
toddouska 0:5045d2638c29 3464
toddouska 0:5045d2638c29 3465 /* can we use the fast multiplier? */
toddouska 0:5045d2638c29 3466 #ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
toddouska 0:5045d2638c29 3467 if (((a->used + b->used + 1) < MP_WARRAY)
toddouska 0:5045d2638c29 3468 && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
toddouska 0:5045d2638c29 3469 return fast_s_mp_mul_high_digs (a, b, c, digs);
toddouska 0:5045d2638c29 3470 }
toddouska 0:5045d2638c29 3471 #endif
toddouska 0:5045d2638c29 3472
toddouska 0:5045d2638c29 3473 if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) {
toddouska 0:5045d2638c29 3474 return res;
toddouska 0:5045d2638c29 3475 }
toddouska 0:5045d2638c29 3476 t.used = a->used + b->used + 1;
toddouska 0:5045d2638c29 3477
toddouska 0:5045d2638c29 3478 pa = a->used;
toddouska 0:5045d2638c29 3479 pb = b->used;
toddouska 0:5045d2638c29 3480 for (ix = 0; ix < pa; ix++) {
toddouska 0:5045d2638c29 3481 /* clear the carry */
toddouska 0:5045d2638c29 3482 u = 0;
toddouska 0:5045d2638c29 3483
toddouska 0:5045d2638c29 3484 /* left hand side of A[ix] * B[iy] */
toddouska 0:5045d2638c29 3485 tmpx = a->dp[ix];
toddouska 0:5045d2638c29 3486
toddouska 0:5045d2638c29 3487 /* alias to the address of where the digits will be stored */
toddouska 0:5045d2638c29 3488 tmpt = &(t.dp[digs]);
toddouska 0:5045d2638c29 3489
toddouska 0:5045d2638c29 3490 /* alias for where to read the right hand side from */
toddouska 0:5045d2638c29 3491 tmpy = b->dp + (digs - ix);
toddouska 0:5045d2638c29 3492
toddouska 0:5045d2638c29 3493 for (iy = digs - ix; iy < pb; iy++) {
toddouska 0:5045d2638c29 3494 /* calculate the double precision result */
toddouska 0:5045d2638c29 3495 r = ((mp_word)*tmpt) +
toddouska 0:5045d2638c29 3496 ((mp_word)tmpx) * ((mp_word)*tmpy++) +
toddouska 0:5045d2638c29 3497 ((mp_word) u);
toddouska 0:5045d2638c29 3498
toddouska 0:5045d2638c29 3499 /* get the lower part */
toddouska 0:5045d2638c29 3500 *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
toddouska 0:5045d2638c29 3501
toddouska 0:5045d2638c29 3502 /* carry the carry */
toddouska 0:5045d2638c29 3503 u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));