cyassl re-port with cellular comms, PSK test

Dependencies:   VodafoneUSBModem_bleedingedge2 mbed-rtos mbed-src

Committer:
ashleymills
Date:
Fri Apr 26 16:54:58 2013 +0000
Revision:
0:e979170e02e7
Basic operation of SSL with PSK working for cellular.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ashleymills 0:e979170e02e7 1 /* integer.c
ashleymills 0:e979170e02e7 2 *
ashleymills 0:e979170e02e7 3 * Copyright (C) 2006-2012 Sawtooth Consulting Ltd.
ashleymills 0:e979170e02e7 4 *
ashleymills 0:e979170e02e7 5 * This file is part of CyaSSL.
ashleymills 0:e979170e02e7 6 *
ashleymills 0:e979170e02e7 7 * CyaSSL is free software; you can redistribute it and/or modify
ashleymills 0:e979170e02e7 8 * it under the terms of the GNU General Public License as published by
ashleymills 0:e979170e02e7 9 * the Free Software Foundation; either version 2 of the License, or
ashleymills 0:e979170e02e7 10 * (at your option) any later version.
ashleymills 0:e979170e02e7 11 *
ashleymills 0:e979170e02e7 12 * CyaSSL is distributed in the hope that it will be useful,
ashleymills 0:e979170e02e7 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
ashleymills 0:e979170e02e7 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
ashleymills 0:e979170e02e7 15 * GNU General Public License for more details.
ashleymills 0:e979170e02e7 16 *
ashleymills 0:e979170e02e7 17 * You should have received a copy of the GNU General Public License
ashleymills 0:e979170e02e7 18 * along with this program; if not, write to the Free Software
ashleymills 0:e979170e02e7 19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
ashleymills 0:e979170e02e7 20 */
ashleymills 0:e979170e02e7 21
ashleymills 0:e979170e02e7 22
ashleymills 0:e979170e02e7 23 /*
ashleymills 0:e979170e02e7 24 * Based on public domain LibTomMath 0.38 by Tom St Denis, tomstdenis@iahu.ca,
ashleymills 0:e979170e02e7 25 * http://math.libtomcrypt.com
ashleymills 0:e979170e02e7 26 */
ashleymills 0:e979170e02e7 27
ashleymills 0:e979170e02e7 28
ashleymills 0:e979170e02e7 29 #ifdef HAVE_CONFIG_H
ashleymills 0:e979170e02e7 30 #include <config.h>
ashleymills 0:e979170e02e7 31 #endif
ashleymills 0:e979170e02e7 32
ashleymills 0:e979170e02e7 33 /* in case user set USE_FAST_MATH there */
ashleymills 0:e979170e02e7 34 #include <cyassl/ctaocrypt/settings.h>
ashleymills 0:e979170e02e7 35
ashleymills 0:e979170e02e7 36 #ifndef USE_FAST_MATH
ashleymills 0:e979170e02e7 37
ashleymills 0:e979170e02e7 38 #include <cyassl/ctaocrypt/integer.h>
ashleymills 0:e979170e02e7 39
ashleymills 0:e979170e02e7 40 #ifndef NO_CYASSL_SMALL_STACK
ashleymills 0:e979170e02e7 41 #ifndef CYASSL_SMALL_STACK
ashleymills 0:e979170e02e7 42 #define CYASSL_SMALL_STACK
ashleymills 0:e979170e02e7 43 #endif
ashleymills 0:e979170e02e7 44 #endif
ashleymills 0:e979170e02e7 45
ashleymills 0:e979170e02e7 46 /* math settings check */
ashleymills 0:e979170e02e7 47 word32 CheckRunTimeSettings(void)
ashleymills 0:e979170e02e7 48 {
ashleymills 0:e979170e02e7 49 return CTC_SETTINGS;
ashleymills 0:e979170e02e7 50 }
ashleymills 0:e979170e02e7 51
ashleymills 0:e979170e02e7 52
ashleymills 0:e979170e02e7 53 /* handle up to 6 inits */
ashleymills 0:e979170e02e7 54 int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e,
ashleymills 0:e979170e02e7 55 mp_int* f)
ashleymills 0:e979170e02e7 56 {
ashleymills 0:e979170e02e7 57 int res = MP_OKAY;
ashleymills 0:e979170e02e7 58
ashleymills 0:e979170e02e7 59 if (a && ((res = mp_init(a)) != MP_OKAY))
ashleymills 0:e979170e02e7 60 return res;
ashleymills 0:e979170e02e7 61
ashleymills 0:e979170e02e7 62 if (b && ((res = mp_init(b)) != MP_OKAY)) {
ashleymills 0:e979170e02e7 63 mp_clear(a);
ashleymills 0:e979170e02e7 64 return res;
ashleymills 0:e979170e02e7 65 }
ashleymills 0:e979170e02e7 66
ashleymills 0:e979170e02e7 67 if (c && ((res = mp_init(c)) != MP_OKAY)) {
ashleymills 0:e979170e02e7 68 mp_clear(a); mp_clear(b);
ashleymills 0:e979170e02e7 69 return res;
ashleymills 0:e979170e02e7 70 }
ashleymills 0:e979170e02e7 71
ashleymills 0:e979170e02e7 72 if (d && ((res = mp_init(d)) != MP_OKAY)) {
ashleymills 0:e979170e02e7 73 mp_clear(a); mp_clear(b); mp_clear(c);
ashleymills 0:e979170e02e7 74 return res;
ashleymills 0:e979170e02e7 75 }
ashleymills 0:e979170e02e7 76
ashleymills 0:e979170e02e7 77 if (e && ((res = mp_init(e)) != MP_OKAY)) {
ashleymills 0:e979170e02e7 78 mp_clear(a); mp_clear(b); mp_clear(c); mp_clear(d);
ashleymills 0:e979170e02e7 79 return res;
ashleymills 0:e979170e02e7 80 }
ashleymills 0:e979170e02e7 81
ashleymills 0:e979170e02e7 82 if (f && ((res = mp_init(f)) != MP_OKAY)) {
ashleymills 0:e979170e02e7 83 mp_clear(a); mp_clear(b); mp_clear(c); mp_clear(d); mp_clear(e);
ashleymills 0:e979170e02e7 84 return res;
ashleymills 0:e979170e02e7 85 }
ashleymills 0:e979170e02e7 86
ashleymills 0:e979170e02e7 87 return res;
ashleymills 0:e979170e02e7 88 }
ashleymills 0:e979170e02e7 89
ashleymills 0:e979170e02e7 90
ashleymills 0:e979170e02e7 91 /* init a new mp_int */
ashleymills 0:e979170e02e7 92 int mp_init (mp_int * a)
ashleymills 0:e979170e02e7 93 {
ashleymills 0:e979170e02e7 94 int i;
ashleymills 0:e979170e02e7 95
ashleymills 0:e979170e02e7 96 /* allocate memory required and clear it */
ashleymills 0:e979170e02e7 97 a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC, 0,
ashleymills 0:e979170e02e7 98 DYNAMIC_TYPE_BIGINT);
ashleymills 0:e979170e02e7 99 if (a->dp == NULL) {
ashleymills 0:e979170e02e7 100 return MP_MEM;
ashleymills 0:e979170e02e7 101 }
ashleymills 0:e979170e02e7 102
ashleymills 0:e979170e02e7 103 /* set the digits to zero */
ashleymills 0:e979170e02e7 104 for (i = 0; i < MP_PREC; i++) {
ashleymills 0:e979170e02e7 105 a->dp[i] = 0;
ashleymills 0:e979170e02e7 106 }
ashleymills 0:e979170e02e7 107
ashleymills 0:e979170e02e7 108 /* set the used to zero, allocated digits to the default precision
ashleymills 0:e979170e02e7 109 * and sign to positive */
ashleymills 0:e979170e02e7 110 a->used = 0;
ashleymills 0:e979170e02e7 111 a->alloc = MP_PREC;
ashleymills 0:e979170e02e7 112 a->sign = MP_ZPOS;
ashleymills 0:e979170e02e7 113
ashleymills 0:e979170e02e7 114 return MP_OKAY;
ashleymills 0:e979170e02e7 115 }
ashleymills 0:e979170e02e7 116
ashleymills 0:e979170e02e7 117
ashleymills 0:e979170e02e7 118 /* clear one (frees) */
ashleymills 0:e979170e02e7 119 void
ashleymills 0:e979170e02e7 120 mp_clear (mp_int * a)
ashleymills 0:e979170e02e7 121 {
ashleymills 0:e979170e02e7 122 int i;
ashleymills 0:e979170e02e7 123
ashleymills 0:e979170e02e7 124 if (a == NULL)
ashleymills 0:e979170e02e7 125 return;
ashleymills 0:e979170e02e7 126
ashleymills 0:e979170e02e7 127 /* only do anything if a hasn't been freed previously */
ashleymills 0:e979170e02e7 128 if (a->dp != NULL) {
ashleymills 0:e979170e02e7 129 /* first zero the digits */
ashleymills 0:e979170e02e7 130 for (i = 0; i < a->used; i++) {
ashleymills 0:e979170e02e7 131 a->dp[i] = 0;
ashleymills 0:e979170e02e7 132 }
ashleymills 0:e979170e02e7 133
ashleymills 0:e979170e02e7 134 /* free ram */
ashleymills 0:e979170e02e7 135 XFREE(a->dp, 0, DYNAMIC_TYPE_BIGINT);
ashleymills 0:e979170e02e7 136
ashleymills 0:e979170e02e7 137 /* reset members to make debugging easier */
ashleymills 0:e979170e02e7 138 a->dp = NULL;
ashleymills 0:e979170e02e7 139 a->alloc = a->used = 0;
ashleymills 0:e979170e02e7 140 a->sign = MP_ZPOS;
ashleymills 0:e979170e02e7 141 }
ashleymills 0:e979170e02e7 142 }
ashleymills 0:e979170e02e7 143
ashleymills 0:e979170e02e7 144
ashleymills 0:e979170e02e7 145 /* get the size for an unsigned equivalent */
ashleymills 0:e979170e02e7 146 int mp_unsigned_bin_size (mp_int * a)
ashleymills 0:e979170e02e7 147 {
ashleymills 0:e979170e02e7 148 int size = mp_count_bits (a);
ashleymills 0:e979170e02e7 149 return (size / 8 + ((size & 7) != 0 ? 1 : 0));
ashleymills 0:e979170e02e7 150 }
ashleymills 0:e979170e02e7 151
ashleymills 0:e979170e02e7 152
ashleymills 0:e979170e02e7 153 /* returns the number of bits in an int */
ashleymills 0:e979170e02e7 154 int
ashleymills 0:e979170e02e7 155 mp_count_bits (mp_int * a)
ashleymills 0:e979170e02e7 156 {
ashleymills 0:e979170e02e7 157 int r;
ashleymills 0:e979170e02e7 158 mp_digit q;
ashleymills 0:e979170e02e7 159
ashleymills 0:e979170e02e7 160 /* shortcut */
ashleymills 0:e979170e02e7 161 if (a->used == 0) {
ashleymills 0:e979170e02e7 162 return 0;
ashleymills 0:e979170e02e7 163 }
ashleymills 0:e979170e02e7 164
ashleymills 0:e979170e02e7 165 /* get number of digits and add that */
ashleymills 0:e979170e02e7 166 r = (a->used - 1) * DIGIT_BIT;
ashleymills 0:e979170e02e7 167
ashleymills 0:e979170e02e7 168 /* take the last digit and count the bits in it */
ashleymills 0:e979170e02e7 169 q = a->dp[a->used - 1];
ashleymills 0:e979170e02e7 170 while (q > ((mp_digit) 0)) {
ashleymills 0:e979170e02e7 171 ++r;
ashleymills 0:e979170e02e7 172 q >>= ((mp_digit) 1);
ashleymills 0:e979170e02e7 173 }
ashleymills 0:e979170e02e7 174 return r;
ashleymills 0:e979170e02e7 175 }
ashleymills 0:e979170e02e7 176
ashleymills 0:e979170e02e7 177
ashleymills 0:e979170e02e7 178 /* store in unsigned [big endian] format */
ashleymills 0:e979170e02e7 179 int mp_to_unsigned_bin (mp_int * a, unsigned char *b)
ashleymills 0:e979170e02e7 180 {
ashleymills 0:e979170e02e7 181 int x, res;
ashleymills 0:e979170e02e7 182 mp_int t;
ashleymills 0:e979170e02e7 183
ashleymills 0:e979170e02e7 184 if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
ashleymills 0:e979170e02e7 185 return res;
ashleymills 0:e979170e02e7 186 }
ashleymills 0:e979170e02e7 187
ashleymills 0:e979170e02e7 188 x = 0;
ashleymills 0:e979170e02e7 189 while (mp_iszero (&t) == 0) {
ashleymills 0:e979170e02e7 190 #ifndef MP_8BIT
ashleymills 0:e979170e02e7 191 b[x++] = (unsigned char) (t.dp[0] & 255);
ashleymills 0:e979170e02e7 192 #else
ashleymills 0:e979170e02e7 193 b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7));
ashleymills 0:e979170e02e7 194 #endif
ashleymills 0:e979170e02e7 195 if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) {
ashleymills 0:e979170e02e7 196 mp_clear (&t);
ashleymills 0:e979170e02e7 197 return res;
ashleymills 0:e979170e02e7 198 }
ashleymills 0:e979170e02e7 199 }
ashleymills 0:e979170e02e7 200 bn_reverse (b, x);
ashleymills 0:e979170e02e7 201 mp_clear (&t);
ashleymills 0:e979170e02e7 202 return MP_OKAY;
ashleymills 0:e979170e02e7 203 }
ashleymills 0:e979170e02e7 204
ashleymills 0:e979170e02e7 205
ashleymills 0:e979170e02e7 206 /* creates "a" then copies b into it */
ashleymills 0:e979170e02e7 207 int mp_init_copy (mp_int * a, mp_int * b)
ashleymills 0:e979170e02e7 208 {
ashleymills 0:e979170e02e7 209 int res;
ashleymills 0:e979170e02e7 210
ashleymills 0:e979170e02e7 211 if ((res = mp_init (a)) != MP_OKAY) {
ashleymills 0:e979170e02e7 212 return res;
ashleymills 0:e979170e02e7 213 }
ashleymills 0:e979170e02e7 214 return mp_copy (b, a);
ashleymills 0:e979170e02e7 215 }
ashleymills 0:e979170e02e7 216
ashleymills 0:e979170e02e7 217
ashleymills 0:e979170e02e7 218 /* copy, b = a */
ashleymills 0:e979170e02e7 219 int
ashleymills 0:e979170e02e7 220 mp_copy (mp_int * a, mp_int * b)
ashleymills 0:e979170e02e7 221 {
ashleymills 0:e979170e02e7 222 int res, n;
ashleymills 0:e979170e02e7 223
ashleymills 0:e979170e02e7 224 /* if dst == src do nothing */
ashleymills 0:e979170e02e7 225 if (a == b) {
ashleymills 0:e979170e02e7 226 return MP_OKAY;
ashleymills 0:e979170e02e7 227 }
ashleymills 0:e979170e02e7 228
ashleymills 0:e979170e02e7 229 /* grow dest */
ashleymills 0:e979170e02e7 230 if (b->alloc < a->used) {
ashleymills 0:e979170e02e7 231 if ((res = mp_grow (b, a->used)) != MP_OKAY) {
ashleymills 0:e979170e02e7 232 return res;
ashleymills 0:e979170e02e7 233 }
ashleymills 0:e979170e02e7 234 }
ashleymills 0:e979170e02e7 235
ashleymills 0:e979170e02e7 236 /* zero b and copy the parameters over */
ashleymills 0:e979170e02e7 237 {
ashleymills 0:e979170e02e7 238 register mp_digit *tmpa, *tmpb;
ashleymills 0:e979170e02e7 239
ashleymills 0:e979170e02e7 240 /* pointer aliases */
ashleymills 0:e979170e02e7 241
ashleymills 0:e979170e02e7 242 /* source */
ashleymills 0:e979170e02e7 243 tmpa = a->dp;
ashleymills 0:e979170e02e7 244
ashleymills 0:e979170e02e7 245 /* destination */
ashleymills 0:e979170e02e7 246 tmpb = b->dp;
ashleymills 0:e979170e02e7 247
ashleymills 0:e979170e02e7 248 /* copy all the digits */
ashleymills 0:e979170e02e7 249 for (n = 0; n < a->used; n++) {
ashleymills 0:e979170e02e7 250 *tmpb++ = *tmpa++;
ashleymills 0:e979170e02e7 251 }
ashleymills 0:e979170e02e7 252
ashleymills 0:e979170e02e7 253 /* clear high digits */
ashleymills 0:e979170e02e7 254 for (; n < b->used; n++) {
ashleymills 0:e979170e02e7 255 *tmpb++ = 0;
ashleymills 0:e979170e02e7 256 }
ashleymills 0:e979170e02e7 257 }
ashleymills 0:e979170e02e7 258
ashleymills 0:e979170e02e7 259 /* copy used count and sign */
ashleymills 0:e979170e02e7 260 b->used = a->used;
ashleymills 0:e979170e02e7 261 b->sign = a->sign;
ashleymills 0:e979170e02e7 262 return MP_OKAY;
ashleymills 0:e979170e02e7 263 }
ashleymills 0:e979170e02e7 264
ashleymills 0:e979170e02e7 265
ashleymills 0:e979170e02e7 266 /* grow as required */
ashleymills 0:e979170e02e7 267 int mp_grow (mp_int * a, int size)
ashleymills 0:e979170e02e7 268 {
ashleymills 0:e979170e02e7 269 int i;
ashleymills 0:e979170e02e7 270 mp_digit *tmp;
ashleymills 0:e979170e02e7 271
ashleymills 0:e979170e02e7 272 /* if the alloc size is smaller alloc more ram */
ashleymills 0:e979170e02e7 273 if (a->alloc < size) {
ashleymills 0:e979170e02e7 274 /* ensure there are always at least MP_PREC digits extra on top */
ashleymills 0:e979170e02e7 275 size += (MP_PREC * 2) - (size % MP_PREC);
ashleymills 0:e979170e02e7 276
ashleymills 0:e979170e02e7 277 /* reallocate the array a->dp
ashleymills 0:e979170e02e7 278 *
ashleymills 0:e979170e02e7 279 * We store the return in a temporary variable
ashleymills 0:e979170e02e7 280 * in case the operation failed we don't want
ashleymills 0:e979170e02e7 281 * to overwrite the dp member of a.
ashleymills 0:e979170e02e7 282 */
ashleymills 0:e979170e02e7 283 tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size, 0,
ashleymills 0:e979170e02e7 284 DYNAMIC_TYPE_BIGINT);
ashleymills 0:e979170e02e7 285 if (tmp == NULL) {
ashleymills 0:e979170e02e7 286 /* reallocation failed but "a" is still valid [can be freed] */
ashleymills 0:e979170e02e7 287 return MP_MEM;
ashleymills 0:e979170e02e7 288 }
ashleymills 0:e979170e02e7 289
ashleymills 0:e979170e02e7 290 /* reallocation succeeded so set a->dp */
ashleymills 0:e979170e02e7 291 a->dp = tmp;
ashleymills 0:e979170e02e7 292
ashleymills 0:e979170e02e7 293 /* zero excess digits */
ashleymills 0:e979170e02e7 294 i = a->alloc;
ashleymills 0:e979170e02e7 295 a->alloc = size;
ashleymills 0:e979170e02e7 296 for (; i < a->alloc; i++) {
ashleymills 0:e979170e02e7 297 a->dp[i] = 0;
ashleymills 0:e979170e02e7 298 }
ashleymills 0:e979170e02e7 299 }
ashleymills 0:e979170e02e7 300 return MP_OKAY;
ashleymills 0:e979170e02e7 301 }
ashleymills 0:e979170e02e7 302
ashleymills 0:e979170e02e7 303
ashleymills 0:e979170e02e7 304 /* reverse an array, used for radix code */
ashleymills 0:e979170e02e7 305 void
ashleymills 0:e979170e02e7 306 bn_reverse (unsigned char *s, int len)
ashleymills 0:e979170e02e7 307 {
ashleymills 0:e979170e02e7 308 int ix, iy;
ashleymills 0:e979170e02e7 309 unsigned char t;
ashleymills 0:e979170e02e7 310
ashleymills 0:e979170e02e7 311 ix = 0;
ashleymills 0:e979170e02e7 312 iy = len - 1;
ashleymills 0:e979170e02e7 313 while (ix < iy) {
ashleymills 0:e979170e02e7 314 t = s[ix];
ashleymills 0:e979170e02e7 315 s[ix] = s[iy];
ashleymills 0:e979170e02e7 316 s[iy] = t;
ashleymills 0:e979170e02e7 317 ++ix;
ashleymills 0:e979170e02e7 318 --iy;
ashleymills 0:e979170e02e7 319 }
ashleymills 0:e979170e02e7 320 }
ashleymills 0:e979170e02e7 321
ashleymills 0:e979170e02e7 322
ashleymills 0:e979170e02e7 323 /* shift right by a certain bit count (store quotient in c, optional
ashleymills 0:e979170e02e7 324 remainder in d) */
ashleymills 0:e979170e02e7 325 int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
ashleymills 0:e979170e02e7 326 {
ashleymills 0:e979170e02e7 327 mp_digit D, r, rr;
ashleymills 0:e979170e02e7 328 int x, res;
ashleymills 0:e979170e02e7 329 mp_int t;
ashleymills 0:e979170e02e7 330
ashleymills 0:e979170e02e7 331
ashleymills 0:e979170e02e7 332 /* if the shift count is <= 0 then we do no work */
ashleymills 0:e979170e02e7 333 if (b <= 0) {
ashleymills 0:e979170e02e7 334 res = mp_copy (a, c);
ashleymills 0:e979170e02e7 335 if (d != NULL) {
ashleymills 0:e979170e02e7 336 mp_zero (d);
ashleymills 0:e979170e02e7 337 }
ashleymills 0:e979170e02e7 338 return res;
ashleymills 0:e979170e02e7 339 }
ashleymills 0:e979170e02e7 340
ashleymills 0:e979170e02e7 341 if ((res = mp_init (&t)) != MP_OKAY) {
ashleymills 0:e979170e02e7 342 return res;
ashleymills 0:e979170e02e7 343 }
ashleymills 0:e979170e02e7 344
ashleymills 0:e979170e02e7 345 /* get the remainder */
ashleymills 0:e979170e02e7 346 if (d != NULL) {
ashleymills 0:e979170e02e7 347 if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
ashleymills 0:e979170e02e7 348 mp_clear (&t);
ashleymills 0:e979170e02e7 349 return res;
ashleymills 0:e979170e02e7 350 }
ashleymills 0:e979170e02e7 351 }
ashleymills 0:e979170e02e7 352
ashleymills 0:e979170e02e7 353 /* copy */
ashleymills 0:e979170e02e7 354 if ((res = mp_copy (a, c)) != MP_OKAY) {
ashleymills 0:e979170e02e7 355 mp_clear (&t);
ashleymills 0:e979170e02e7 356 return res;
ashleymills 0:e979170e02e7 357 }
ashleymills 0:e979170e02e7 358
ashleymills 0:e979170e02e7 359 /* shift by as many digits in the bit count */
ashleymills 0:e979170e02e7 360 if (b >= (int)DIGIT_BIT) {
ashleymills 0:e979170e02e7 361 mp_rshd (c, b / DIGIT_BIT);
ashleymills 0:e979170e02e7 362 }
ashleymills 0:e979170e02e7 363
ashleymills 0:e979170e02e7 364 /* shift any bit count < DIGIT_BIT */
ashleymills 0:e979170e02e7 365 D = (mp_digit) (b % DIGIT_BIT);
ashleymills 0:e979170e02e7 366 if (D != 0) {
ashleymills 0:e979170e02e7 367 register mp_digit *tmpc, mask, shift;
ashleymills 0:e979170e02e7 368
ashleymills 0:e979170e02e7 369 /* mask */
ashleymills 0:e979170e02e7 370 mask = (((mp_digit)1) << D) - 1;
ashleymills 0:e979170e02e7 371
ashleymills 0:e979170e02e7 372 /* shift for lsb */
ashleymills 0:e979170e02e7 373 shift = DIGIT_BIT - D;
ashleymills 0:e979170e02e7 374
ashleymills 0:e979170e02e7 375 /* alias */
ashleymills 0:e979170e02e7 376 tmpc = c->dp + (c->used - 1);
ashleymills 0:e979170e02e7 377
ashleymills 0:e979170e02e7 378 /* carry */
ashleymills 0:e979170e02e7 379 r = 0;
ashleymills 0:e979170e02e7 380 for (x = c->used - 1; x >= 0; x--) {
ashleymills 0:e979170e02e7 381 /* get the lower bits of this word in a temp */
ashleymills 0:e979170e02e7 382 rr = *tmpc & mask;
ashleymills 0:e979170e02e7 383
ashleymills 0:e979170e02e7 384 /* shift the current word and mix in the carry bits from the previous
ashleymills 0:e979170e02e7 385 word */
ashleymills 0:e979170e02e7 386 *tmpc = (*tmpc >> D) | (r << shift);
ashleymills 0:e979170e02e7 387 --tmpc;
ashleymills 0:e979170e02e7 388
ashleymills 0:e979170e02e7 389 /* set the carry to the carry bits of the current word found above */
ashleymills 0:e979170e02e7 390 r = rr;
ashleymills 0:e979170e02e7 391 }
ashleymills 0:e979170e02e7 392 }
ashleymills 0:e979170e02e7 393 mp_clamp (c);
ashleymills 0:e979170e02e7 394 if (d != NULL) {
ashleymills 0:e979170e02e7 395 mp_exch (&t, d);
ashleymills 0:e979170e02e7 396 }
ashleymills 0:e979170e02e7 397 mp_clear (&t);
ashleymills 0:e979170e02e7 398 return MP_OKAY;
ashleymills 0:e979170e02e7 399 }
ashleymills 0:e979170e02e7 400
ashleymills 0:e979170e02e7 401
ashleymills 0:e979170e02e7 402 /* set to zero */
ashleymills 0:e979170e02e7 403 void mp_zero (mp_int * a)
ashleymills 0:e979170e02e7 404 {
ashleymills 0:e979170e02e7 405 int n;
ashleymills 0:e979170e02e7 406 mp_digit *tmp;
ashleymills 0:e979170e02e7 407
ashleymills 0:e979170e02e7 408 a->sign = MP_ZPOS;
ashleymills 0:e979170e02e7 409 a->used = 0;
ashleymills 0:e979170e02e7 410
ashleymills 0:e979170e02e7 411 tmp = a->dp;
ashleymills 0:e979170e02e7 412 for (n = 0; n < a->alloc; n++) {
ashleymills 0:e979170e02e7 413 *tmp++ = 0;
ashleymills 0:e979170e02e7 414 }
ashleymills 0:e979170e02e7 415 }
ashleymills 0:e979170e02e7 416
ashleymills 0:e979170e02e7 417
ashleymills 0:e979170e02e7 418 /* trim unused digits
ashleymills 0:e979170e02e7 419 *
ashleymills 0:e979170e02e7 420 * This is used to ensure that leading zero digits are
ashleymills 0:e979170e02e7 421 * trimed and the leading "used" digit will be non-zero
ashleymills 0:e979170e02e7 422 * Typically very fast. Also fixes the sign if there
ashleymills 0:e979170e02e7 423 * are no more leading digits
ashleymills 0:e979170e02e7 424 */
ashleymills 0:e979170e02e7 425 void
ashleymills 0:e979170e02e7 426 mp_clamp (mp_int * a)
ashleymills 0:e979170e02e7 427 {
ashleymills 0:e979170e02e7 428 /* decrease used while the most significant digit is
ashleymills 0:e979170e02e7 429 * zero.
ashleymills 0:e979170e02e7 430 */
ashleymills 0:e979170e02e7 431 while (a->used > 0 && a->dp[a->used - 1] == 0) {
ashleymills 0:e979170e02e7 432 --(a->used);
ashleymills 0:e979170e02e7 433 }
ashleymills 0:e979170e02e7 434
ashleymills 0:e979170e02e7 435 /* reset the sign flag if used == 0 */
ashleymills 0:e979170e02e7 436 if (a->used == 0) {
ashleymills 0:e979170e02e7 437 a->sign = MP_ZPOS;
ashleymills 0:e979170e02e7 438 }
ashleymills 0:e979170e02e7 439 }
ashleymills 0:e979170e02e7 440
ashleymills 0:e979170e02e7 441
ashleymills 0:e979170e02e7 442 /* swap the elements of two integers, for cases where you can't simply swap the
ashleymills 0:e979170e02e7 443 * mp_int pointers around
ashleymills 0:e979170e02e7 444 */
ashleymills 0:e979170e02e7 445 void
ashleymills 0:e979170e02e7 446 mp_exch (mp_int * a, mp_int * b)
ashleymills 0:e979170e02e7 447 {
ashleymills 0:e979170e02e7 448 mp_int t;
ashleymills 0:e979170e02e7 449
ashleymills 0:e979170e02e7 450 t = *a;
ashleymills 0:e979170e02e7 451 *a = *b;
ashleymills 0:e979170e02e7 452 *b = t;
ashleymills 0:e979170e02e7 453 }
ashleymills 0:e979170e02e7 454
ashleymills 0:e979170e02e7 455
ashleymills 0:e979170e02e7 456 /* shift right a certain amount of digits */
ashleymills 0:e979170e02e7 457 void mp_rshd (mp_int * a, int b)
ashleymills 0:e979170e02e7 458 {
ashleymills 0:e979170e02e7 459 int x;
ashleymills 0:e979170e02e7 460
ashleymills 0:e979170e02e7 461 /* if b <= 0 then ignore it */
ashleymills 0:e979170e02e7 462 if (b <= 0) {
ashleymills 0:e979170e02e7 463 return;
ashleymills 0:e979170e02e7 464 }
ashleymills 0:e979170e02e7 465
ashleymills 0:e979170e02e7 466 /* if b > used then simply zero it and return */
ashleymills 0:e979170e02e7 467 if (a->used <= b) {
ashleymills 0:e979170e02e7 468 mp_zero (a);
ashleymills 0:e979170e02e7 469 return;
ashleymills 0:e979170e02e7 470 }
ashleymills 0:e979170e02e7 471
ashleymills 0:e979170e02e7 472 {
ashleymills 0:e979170e02e7 473 register mp_digit *bottom, *top;
ashleymills 0:e979170e02e7 474
ashleymills 0:e979170e02e7 475 /* shift the digits down */
ashleymills 0:e979170e02e7 476
ashleymills 0:e979170e02e7 477 /* bottom */
ashleymills 0:e979170e02e7 478 bottom = a->dp;
ashleymills 0:e979170e02e7 479
ashleymills 0:e979170e02e7 480 /* top [offset into digits] */
ashleymills 0:e979170e02e7 481 top = a->dp + b;
ashleymills 0:e979170e02e7 482
ashleymills 0:e979170e02e7 483 /* this is implemented as a sliding window where
ashleymills 0:e979170e02e7 484 * the window is b-digits long and digits from
ashleymills 0:e979170e02e7 485 * the top of the window are copied to the bottom
ashleymills 0:e979170e02e7 486 *
ashleymills 0:e979170e02e7 487 * e.g.
ashleymills 0:e979170e02e7 488
ashleymills 0:e979170e02e7 489 b-2 | b-1 | b0 | b1 | b2 | ... | bb | ---->
ashleymills 0:e979170e02e7 490 /\ | ---->
ashleymills 0:e979170e02e7 491 \-------------------/ ---->
ashleymills 0:e979170e02e7 492 */
ashleymills 0:e979170e02e7 493 for (x = 0; x < (a->used - b); x++) {
ashleymills 0:e979170e02e7 494 *bottom++ = *top++;
ashleymills 0:e979170e02e7 495 }
ashleymills 0:e979170e02e7 496
ashleymills 0:e979170e02e7 497 /* zero the top digits */
ashleymills 0:e979170e02e7 498 for (; x < a->used; x++) {
ashleymills 0:e979170e02e7 499 *bottom++ = 0;
ashleymills 0:e979170e02e7 500 }
ashleymills 0:e979170e02e7 501 }
ashleymills 0:e979170e02e7 502
ashleymills 0:e979170e02e7 503 /* remove excess digits */
ashleymills 0:e979170e02e7 504 a->used -= b;
ashleymills 0:e979170e02e7 505 }
ashleymills 0:e979170e02e7 506
ashleymills 0:e979170e02e7 507
ashleymills 0:e979170e02e7 508 /* calc a value mod 2**b */
ashleymills 0:e979170e02e7 509 int
ashleymills 0:e979170e02e7 510 mp_mod_2d (mp_int * a, int b, mp_int * c)
ashleymills 0:e979170e02e7 511 {
ashleymills 0:e979170e02e7 512 int x, res;
ashleymills 0:e979170e02e7 513
ashleymills 0:e979170e02e7 514 /* if b is <= 0 then zero the int */
ashleymills 0:e979170e02e7 515 if (b <= 0) {
ashleymills 0:e979170e02e7 516 mp_zero (c);
ashleymills 0:e979170e02e7 517 return MP_OKAY;
ashleymills 0:e979170e02e7 518 }
ashleymills 0:e979170e02e7 519
ashleymills 0:e979170e02e7 520 /* if the modulus is larger than the value than return */
ashleymills 0:e979170e02e7 521 if (b >= (int) (a->used * DIGIT_BIT)) {
ashleymills 0:e979170e02e7 522 res = mp_copy (a, c);
ashleymills 0:e979170e02e7 523 return res;
ashleymills 0:e979170e02e7 524 }
ashleymills 0:e979170e02e7 525
ashleymills 0:e979170e02e7 526 /* copy */
ashleymills 0:e979170e02e7 527 if ((res = mp_copy (a, c)) != MP_OKAY) {
ashleymills 0:e979170e02e7 528 return res;
ashleymills 0:e979170e02e7 529 }
ashleymills 0:e979170e02e7 530
ashleymills 0:e979170e02e7 531 /* zero digits above the last digit of the modulus */
ashleymills 0:e979170e02e7 532 for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
ashleymills 0:e979170e02e7 533 c->dp[x] = 0;
ashleymills 0:e979170e02e7 534 }
ashleymills 0:e979170e02e7 535 /* clear the digit that is not completely outside/inside the modulus */
ashleymills 0:e979170e02e7 536 c->dp[b / DIGIT_BIT] &= (mp_digit) ((((mp_digit) 1) <<
ashleymills 0:e979170e02e7 537 (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1));
ashleymills 0:e979170e02e7 538 mp_clamp (c);
ashleymills 0:e979170e02e7 539 return MP_OKAY;
ashleymills 0:e979170e02e7 540 }
ashleymills 0:e979170e02e7 541
ashleymills 0:e979170e02e7 542
ashleymills 0:e979170e02e7 543 /* reads a unsigned char array, assumes the msb is stored first [big endian] */
ashleymills 0:e979170e02e7 544 int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
ashleymills 0:e979170e02e7 545 {
ashleymills 0:e979170e02e7 546 int res;
ashleymills 0:e979170e02e7 547
ashleymills 0:e979170e02e7 548 /* make sure there are at least two digits */
ashleymills 0:e979170e02e7 549 if (a->alloc < 2) {
ashleymills 0:e979170e02e7 550 if ((res = mp_grow(a, 2)) != MP_OKAY) {
ashleymills 0:e979170e02e7 551 return res;
ashleymills 0:e979170e02e7 552 }
ashleymills 0:e979170e02e7 553 }
ashleymills 0:e979170e02e7 554
ashleymills 0:e979170e02e7 555 /* zero the int */
ashleymills 0:e979170e02e7 556 mp_zero (a);
ashleymills 0:e979170e02e7 557
ashleymills 0:e979170e02e7 558 /* read the bytes in */
ashleymills 0:e979170e02e7 559 while (c-- > 0) {
ashleymills 0:e979170e02e7 560 if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
ashleymills 0:e979170e02e7 561 return res;
ashleymills 0:e979170e02e7 562 }
ashleymills 0:e979170e02e7 563
ashleymills 0:e979170e02e7 564 #ifndef MP_8BIT
ashleymills 0:e979170e02e7 565 a->dp[0] |= *b++;
ashleymills 0:e979170e02e7 566 a->used += 1;
ashleymills 0:e979170e02e7 567 #else
ashleymills 0:e979170e02e7 568 a->dp[0] = (*b & MP_MASK);
ashleymills 0:e979170e02e7 569 a->dp[1] |= ((*b++ >> 7U) & 1);
ashleymills 0:e979170e02e7 570 a->used += 2;
ashleymills 0:e979170e02e7 571 #endif
ashleymills 0:e979170e02e7 572 }
ashleymills 0:e979170e02e7 573 mp_clamp (a);
ashleymills 0:e979170e02e7 574 return MP_OKAY;
ashleymills 0:e979170e02e7 575 }
ashleymills 0:e979170e02e7 576
ashleymills 0:e979170e02e7 577
ashleymills 0:e979170e02e7 578 /* shift left by a certain bit count */
ashleymills 0:e979170e02e7 579 int mp_mul_2d (mp_int * a, int b, mp_int * c)
ashleymills 0:e979170e02e7 580 {
ashleymills 0:e979170e02e7 581 mp_digit d;
ashleymills 0:e979170e02e7 582 int res;
ashleymills 0:e979170e02e7 583
ashleymills 0:e979170e02e7 584 /* copy */
ashleymills 0:e979170e02e7 585 if (a != c) {
ashleymills 0:e979170e02e7 586 if ((res = mp_copy (a, c)) != MP_OKAY) {
ashleymills 0:e979170e02e7 587 return res;
ashleymills 0:e979170e02e7 588 }
ashleymills 0:e979170e02e7 589 }
ashleymills 0:e979170e02e7 590
ashleymills 0:e979170e02e7 591 if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) {
ashleymills 0:e979170e02e7 592 if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
ashleymills 0:e979170e02e7 593 return res;
ashleymills 0:e979170e02e7 594 }
ashleymills 0:e979170e02e7 595 }
ashleymills 0:e979170e02e7 596
ashleymills 0:e979170e02e7 597 /* shift by as many digits in the bit count */
ashleymills 0:e979170e02e7 598 if (b >= (int)DIGIT_BIT) {
ashleymills 0:e979170e02e7 599 if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
ashleymills 0:e979170e02e7 600 return res;
ashleymills 0:e979170e02e7 601 }
ashleymills 0:e979170e02e7 602 }
ashleymills 0:e979170e02e7 603
ashleymills 0:e979170e02e7 604 /* shift any bit count < DIGIT_BIT */
ashleymills 0:e979170e02e7 605 d = (mp_digit) (b % DIGIT_BIT);
ashleymills 0:e979170e02e7 606 if (d != 0) {
ashleymills 0:e979170e02e7 607 register mp_digit *tmpc, shift, mask, r, rr;
ashleymills 0:e979170e02e7 608 register int x;
ashleymills 0:e979170e02e7 609
ashleymills 0:e979170e02e7 610 /* bitmask for carries */
ashleymills 0:e979170e02e7 611 mask = (((mp_digit)1) << d) - 1;
ashleymills 0:e979170e02e7 612
ashleymills 0:e979170e02e7 613 /* shift for msbs */
ashleymills 0:e979170e02e7 614 shift = DIGIT_BIT - d;
ashleymills 0:e979170e02e7 615
ashleymills 0:e979170e02e7 616 /* alias */
ashleymills 0:e979170e02e7 617 tmpc = c->dp;
ashleymills 0:e979170e02e7 618
ashleymills 0:e979170e02e7 619 /* carry */
ashleymills 0:e979170e02e7 620 r = 0;
ashleymills 0:e979170e02e7 621 for (x = 0; x < c->used; x++) {
ashleymills 0:e979170e02e7 622 /* get the higher bits of the current word */
ashleymills 0:e979170e02e7 623 rr = (*tmpc >> shift) & mask;
ashleymills 0:e979170e02e7 624
ashleymills 0:e979170e02e7 625 /* shift the current word and OR in the carry */
ashleymills 0:e979170e02e7 626 *tmpc = ((*tmpc << d) | r) & MP_MASK;
ashleymills 0:e979170e02e7 627 ++tmpc;
ashleymills 0:e979170e02e7 628
ashleymills 0:e979170e02e7 629 /* set the carry to the carry bits of the current word */
ashleymills 0:e979170e02e7 630 r = rr;
ashleymills 0:e979170e02e7 631 }
ashleymills 0:e979170e02e7 632
ashleymills 0:e979170e02e7 633 /* set final carry */
ashleymills 0:e979170e02e7 634 if (r != 0) {
ashleymills 0:e979170e02e7 635 c->dp[(c->used)++] = r;
ashleymills 0:e979170e02e7 636 }
ashleymills 0:e979170e02e7 637 }
ashleymills 0:e979170e02e7 638 mp_clamp (c);
ashleymills 0:e979170e02e7 639 return MP_OKAY;
ashleymills 0:e979170e02e7 640 }
ashleymills 0:e979170e02e7 641
ashleymills 0:e979170e02e7 642
ashleymills 0:e979170e02e7 643 /* shift left a certain amount of digits */
ashleymills 0:e979170e02e7 644 int mp_lshd (mp_int * a, int b)
ashleymills 0:e979170e02e7 645 {
ashleymills 0:e979170e02e7 646 int x, res;
ashleymills 0:e979170e02e7 647
ashleymills 0:e979170e02e7 648 /* if its less than zero return */
ashleymills 0:e979170e02e7 649 if (b <= 0) {
ashleymills 0:e979170e02e7 650 return MP_OKAY;
ashleymills 0:e979170e02e7 651 }
ashleymills 0:e979170e02e7 652
ashleymills 0:e979170e02e7 653 /* grow to fit the new digits */
ashleymills 0:e979170e02e7 654 if (a->alloc < a->used + b) {
ashleymills 0:e979170e02e7 655 if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
ashleymills 0:e979170e02e7 656 return res;
ashleymills 0:e979170e02e7 657 }
ashleymills 0:e979170e02e7 658 }
ashleymills 0:e979170e02e7 659
ashleymills 0:e979170e02e7 660 {
ashleymills 0:e979170e02e7 661 register mp_digit *top, *bottom;
ashleymills 0:e979170e02e7 662
ashleymills 0:e979170e02e7 663 /* increment the used by the shift amount then copy upwards */
ashleymills 0:e979170e02e7 664 a->used += b;
ashleymills 0:e979170e02e7 665
ashleymills 0:e979170e02e7 666 /* top */
ashleymills 0:e979170e02e7 667 top = a->dp + a->used - 1;
ashleymills 0:e979170e02e7 668
ashleymills 0:e979170e02e7 669 /* base */
ashleymills 0:e979170e02e7 670 bottom = a->dp + a->used - 1 - b;
ashleymills 0:e979170e02e7 671
ashleymills 0:e979170e02e7 672 /* much like mp_rshd this is implemented using a sliding window
ashleymills 0:e979170e02e7 673 * except the window goes the otherway around. Copying from
ashleymills 0:e979170e02e7 674 * the bottom to the top. see bn_mp_rshd.c for more info.
ashleymills 0:e979170e02e7 675 */
ashleymills 0:e979170e02e7 676 for (x = a->used - 1; x >= b; x--) {
ashleymills 0:e979170e02e7 677 *top-- = *bottom--;
ashleymills 0:e979170e02e7 678 }
ashleymills 0:e979170e02e7 679
ashleymills 0:e979170e02e7 680 /* zero the lower digits */
ashleymills 0:e979170e02e7 681 top = a->dp;
ashleymills 0:e979170e02e7 682 for (x = 0; x < b; x++) {
ashleymills 0:e979170e02e7 683 *top++ = 0;
ashleymills 0:e979170e02e7 684 }
ashleymills 0:e979170e02e7 685 }
ashleymills 0:e979170e02e7 686 return MP_OKAY;
ashleymills 0:e979170e02e7 687 }
ashleymills 0:e979170e02e7 688
ashleymills 0:e979170e02e7 689
ashleymills 0:e979170e02e7 690 /* this is a shell function that calls either the normal or Montgomery
ashleymills 0:e979170e02e7 691 * exptmod functions. Originally the call to the montgomery code was
ashleymills 0:e979170e02e7 692 * embedded in the normal function but that wasted alot of stack space
ashleymills 0:e979170e02e7 693 * for nothing (since 99% of the time the Montgomery code would be called)
ashleymills 0:e979170e02e7 694 */
ashleymills 0:e979170e02e7 695 int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
ashleymills 0:e979170e02e7 696 {
ashleymills 0:e979170e02e7 697 int dr;
ashleymills 0:e979170e02e7 698
ashleymills 0:e979170e02e7 699 /* modulus P must be positive */
ashleymills 0:e979170e02e7 700 if (P->sign == MP_NEG) {
ashleymills 0:e979170e02e7 701 return MP_VAL;
ashleymills 0:e979170e02e7 702 }
ashleymills 0:e979170e02e7 703
ashleymills 0:e979170e02e7 704 /* if exponent X is negative we have to recurse */
ashleymills 0:e979170e02e7 705 if (X->sign == MP_NEG) {
ashleymills 0:e979170e02e7 706 #ifdef BN_MP_INVMOD_C
ashleymills 0:e979170e02e7 707 mp_int tmpG, tmpX;
ashleymills 0:e979170e02e7 708 int err;
ashleymills 0:e979170e02e7 709
ashleymills 0:e979170e02e7 710 /* first compute 1/G mod P */
ashleymills 0:e979170e02e7 711 if ((err = mp_init(&tmpG)) != MP_OKAY) {
ashleymills 0:e979170e02e7 712 return err;
ashleymills 0:e979170e02e7 713 }
ashleymills 0:e979170e02e7 714 if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
ashleymills 0:e979170e02e7 715 mp_clear(&tmpG);
ashleymills 0:e979170e02e7 716 return err;
ashleymills 0:e979170e02e7 717 }
ashleymills 0:e979170e02e7 718
ashleymills 0:e979170e02e7 719 /* now get |X| */
ashleymills 0:e979170e02e7 720 if ((err = mp_init(&tmpX)) != MP_OKAY) {
ashleymills 0:e979170e02e7 721 mp_clear(&tmpG);
ashleymills 0:e979170e02e7 722 return err;
ashleymills 0:e979170e02e7 723 }
ashleymills 0:e979170e02e7 724 if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
ashleymills 0:e979170e02e7 725 mp_clear(&tmpG);
ashleymills 0:e979170e02e7 726 mp_clear(&tmpX);
ashleymills 0:e979170e02e7 727 return err;
ashleymills 0:e979170e02e7 728 }
ashleymills 0:e979170e02e7 729
ashleymills 0:e979170e02e7 730 /* and now compute (1/G)**|X| instead of G**X [X < 0] */
ashleymills 0:e979170e02e7 731 err = mp_exptmod(&tmpG, &tmpX, P, Y);
ashleymills 0:e979170e02e7 732 mp_clear(&tmpG);
ashleymills 0:e979170e02e7 733 mp_clear(&tmpX);
ashleymills 0:e979170e02e7 734 return err;
ashleymills 0:e979170e02e7 735 #else
ashleymills 0:e979170e02e7 736 /* no invmod */
ashleymills 0:e979170e02e7 737 return MP_VAL;
ashleymills 0:e979170e02e7 738 #endif
ashleymills 0:e979170e02e7 739 }
ashleymills 0:e979170e02e7 740
ashleymills 0:e979170e02e7 741 /* modified diminished radix reduction */
ashleymills 0:e979170e02e7 742 #if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && \
ashleymills 0:e979170e02e7 743 defined(BN_S_MP_EXPTMOD_C)
ashleymills 0:e979170e02e7 744 if (mp_reduce_is_2k_l(P) == MP_YES) {
ashleymills 0:e979170e02e7 745 return s_mp_exptmod(G, X, P, Y, 1);
ashleymills 0:e979170e02e7 746 }
ashleymills 0:e979170e02e7 747 #endif
ashleymills 0:e979170e02e7 748
ashleymills 0:e979170e02e7 749 #ifdef BN_MP_DR_IS_MODULUS_C
ashleymills 0:e979170e02e7 750 /* is it a DR modulus? */
ashleymills 0:e979170e02e7 751 dr = mp_dr_is_modulus(P);
ashleymills 0:e979170e02e7 752 #else
ashleymills 0:e979170e02e7 753 /* default to no */
ashleymills 0:e979170e02e7 754 dr = 0;
ashleymills 0:e979170e02e7 755 #endif
ashleymills 0:e979170e02e7 756
ashleymills 0:e979170e02e7 757 #ifdef BN_MP_REDUCE_IS_2K_C
ashleymills 0:e979170e02e7 758 /* if not, is it a unrestricted DR modulus? */
ashleymills 0:e979170e02e7 759 if (dr == 0) {
ashleymills 0:e979170e02e7 760 dr = mp_reduce_is_2k(P) << 1;
ashleymills 0:e979170e02e7 761 }
ashleymills 0:e979170e02e7 762 #endif
ashleymills 0:e979170e02e7 763
ashleymills 0:e979170e02e7 764 /* if the modulus is odd or dr != 0 use the montgomery method */
ashleymills 0:e979170e02e7 765 #ifdef BN_MP_EXPTMOD_FAST_C
ashleymills 0:e979170e02e7 766 if (mp_isodd (P) == 1 || dr != 0) {
ashleymills 0:e979170e02e7 767 return mp_exptmod_fast (G, X, P, Y, dr);
ashleymills 0:e979170e02e7 768 } else {
ashleymills 0:e979170e02e7 769 #endif
ashleymills 0:e979170e02e7 770 #ifdef BN_S_MP_EXPTMOD_C
ashleymills 0:e979170e02e7 771 /* otherwise use the generic Barrett reduction technique */
ashleymills 0:e979170e02e7 772 return s_mp_exptmod (G, X, P, Y, 0);
ashleymills 0:e979170e02e7 773 #else
ashleymills 0:e979170e02e7 774 /* no exptmod for evens */
ashleymills 0:e979170e02e7 775 return MP_VAL;
ashleymills 0:e979170e02e7 776 #endif
ashleymills 0:e979170e02e7 777 #ifdef BN_MP_EXPTMOD_FAST_C
ashleymills 0:e979170e02e7 778 }
ashleymills 0:e979170e02e7 779 #endif
ashleymills 0:e979170e02e7 780 }
ashleymills 0:e979170e02e7 781
ashleymills 0:e979170e02e7 782
ashleymills 0:e979170e02e7 783 /* b = |a|
ashleymills 0:e979170e02e7 784 *
ashleymills 0:e979170e02e7 785 * Simple function copies the input and fixes the sign to positive
ashleymills 0:e979170e02e7 786 */
ashleymills 0:e979170e02e7 787 int
ashleymills 0:e979170e02e7 788 mp_abs (mp_int * a, mp_int * b)
ashleymills 0:e979170e02e7 789 {
ashleymills 0:e979170e02e7 790 int res;
ashleymills 0:e979170e02e7 791
ashleymills 0:e979170e02e7 792 /* copy a to b */
ashleymills 0:e979170e02e7 793 if (a != b) {
ashleymills 0:e979170e02e7 794 if ((res = mp_copy (a, b)) != MP_OKAY) {
ashleymills 0:e979170e02e7 795 return res;
ashleymills 0:e979170e02e7 796 }
ashleymills 0:e979170e02e7 797 }
ashleymills 0:e979170e02e7 798
ashleymills 0:e979170e02e7 799 /* force the sign of b to positive */
ashleymills 0:e979170e02e7 800 b->sign = MP_ZPOS;
ashleymills 0:e979170e02e7 801
ashleymills 0:e979170e02e7 802 return MP_OKAY;
ashleymills 0:e979170e02e7 803 }
ashleymills 0:e979170e02e7 804
ashleymills 0:e979170e02e7 805
ashleymills 0:e979170e02e7 806 /* hac 14.61, pp608 */
ashleymills 0:e979170e02e7 807 int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
ashleymills 0:e979170e02e7 808 {
ashleymills 0:e979170e02e7 809 /* b cannot be negative */
ashleymills 0:e979170e02e7 810 if (b->sign == MP_NEG || mp_iszero(b) == 1) {
ashleymills 0:e979170e02e7 811 return MP_VAL;
ashleymills 0:e979170e02e7 812 }
ashleymills 0:e979170e02e7 813
ashleymills 0:e979170e02e7 814 #ifdef BN_FAST_MP_INVMOD_C
ashleymills 0:e979170e02e7 815 /* if the modulus is odd we can use a faster routine instead */
ashleymills 0:e979170e02e7 816 if (mp_isodd (b) == 1) {
ashleymills 0:e979170e02e7 817 return fast_mp_invmod (a, b, c);
ashleymills 0:e979170e02e7 818 }
ashleymills 0:e979170e02e7 819 #endif
ashleymills 0:e979170e02e7 820
ashleymills 0:e979170e02e7 821 #ifdef BN_MP_INVMOD_SLOW_C
ashleymills 0:e979170e02e7 822 return mp_invmod_slow(a, b, c);
ashleymills 0:e979170e02e7 823 #endif
ashleymills 0:e979170e02e7 824 }
ashleymills 0:e979170e02e7 825
ashleymills 0:e979170e02e7 826
ashleymills 0:e979170e02e7 827 /* computes the modular inverse via binary extended euclidean algorithm,
ashleymills 0:e979170e02e7 828 * that is c = 1/a mod b
ashleymills 0:e979170e02e7 829 *
ashleymills 0:e979170e02e7 830 * Based on slow invmod except this is optimized for the case where b is
ashleymills 0:e979170e02e7 831 * odd as per HAC Note 14.64 on pp. 610
ashleymills 0:e979170e02e7 832 */
ashleymills 0:e979170e02e7 833 int fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c)
ashleymills 0:e979170e02e7 834 {
ashleymills 0:e979170e02e7 835 mp_int x, y, u, v, B, D;
ashleymills 0:e979170e02e7 836 int res, neg;
ashleymills 0:e979170e02e7 837
ashleymills 0:e979170e02e7 838 /* 2. [modified] b must be odd */
ashleymills 0:e979170e02e7 839 if (mp_iseven (b) == 1) {
ashleymills 0:e979170e02e7 840 return MP_VAL;
ashleymills 0:e979170e02e7 841 }
ashleymills 0:e979170e02e7 842
ashleymills 0:e979170e02e7 843 /* init all our temps */
ashleymills 0:e979170e02e7 844 if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D)) != MP_OKAY) {
ashleymills 0:e979170e02e7 845 return res;
ashleymills 0:e979170e02e7 846 }
ashleymills 0:e979170e02e7 847
ashleymills 0:e979170e02e7 848 /* x == modulus, y == value to invert */
ashleymills 0:e979170e02e7 849 if ((res = mp_copy (b, &x)) != MP_OKAY) {
ashleymills 0:e979170e02e7 850 goto LBL_ERR;
ashleymills 0:e979170e02e7 851 }
ashleymills 0:e979170e02e7 852
ashleymills 0:e979170e02e7 853 /* we need y = |a| */
ashleymills 0:e979170e02e7 854 if ((res = mp_mod (a, b, &y)) != MP_OKAY) {
ashleymills 0:e979170e02e7 855 goto LBL_ERR;
ashleymills 0:e979170e02e7 856 }
ashleymills 0:e979170e02e7 857
ashleymills 0:e979170e02e7 858 /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
ashleymills 0:e979170e02e7 859 if ((res = mp_copy (&x, &u)) != MP_OKAY) {
ashleymills 0:e979170e02e7 860 goto LBL_ERR;
ashleymills 0:e979170e02e7 861 }
ashleymills 0:e979170e02e7 862 if ((res = mp_copy (&y, &v)) != MP_OKAY) {
ashleymills 0:e979170e02e7 863 goto LBL_ERR;
ashleymills 0:e979170e02e7 864 }
ashleymills 0:e979170e02e7 865 mp_set (&D, 1);
ashleymills 0:e979170e02e7 866
ashleymills 0:e979170e02e7 867 top:
ashleymills 0:e979170e02e7 868 /* 4. while u is even do */
ashleymills 0:e979170e02e7 869 while (mp_iseven (&u) == 1) {
ashleymills 0:e979170e02e7 870 /* 4.1 u = u/2 */
ashleymills 0:e979170e02e7 871 if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
ashleymills 0:e979170e02e7 872 goto LBL_ERR;
ashleymills 0:e979170e02e7 873 }
ashleymills 0:e979170e02e7 874 /* 4.2 if B is odd then */
ashleymills 0:e979170e02e7 875 if (mp_isodd (&B) == 1) {
ashleymills 0:e979170e02e7 876 if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
ashleymills 0:e979170e02e7 877 goto LBL_ERR;
ashleymills 0:e979170e02e7 878 }
ashleymills 0:e979170e02e7 879 }
ashleymills 0:e979170e02e7 880 /* B = B/2 */
ashleymills 0:e979170e02e7 881 if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
ashleymills 0:e979170e02e7 882 goto LBL_ERR;
ashleymills 0:e979170e02e7 883 }
ashleymills 0:e979170e02e7 884 }
ashleymills 0:e979170e02e7 885
ashleymills 0:e979170e02e7 886 /* 5. while v is even do */
ashleymills 0:e979170e02e7 887 while (mp_iseven (&v) == 1) {
ashleymills 0:e979170e02e7 888 /* 5.1 v = v/2 */
ashleymills 0:e979170e02e7 889 if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
ashleymills 0:e979170e02e7 890 goto LBL_ERR;
ashleymills 0:e979170e02e7 891 }
ashleymills 0:e979170e02e7 892 /* 5.2 if D is odd then */
ashleymills 0:e979170e02e7 893 if (mp_isodd (&D) == 1) {
ashleymills 0:e979170e02e7 894 /* D = (D-x)/2 */
ashleymills 0:e979170e02e7 895 if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
ashleymills 0:e979170e02e7 896 goto LBL_ERR;
ashleymills 0:e979170e02e7 897 }
ashleymills 0:e979170e02e7 898 }
ashleymills 0:e979170e02e7 899 /* D = D/2 */
ashleymills 0:e979170e02e7 900 if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
ashleymills 0:e979170e02e7 901 goto LBL_ERR;
ashleymills 0:e979170e02e7 902 }
ashleymills 0:e979170e02e7 903 }
ashleymills 0:e979170e02e7 904
ashleymills 0:e979170e02e7 905 /* 6. if u >= v then */
ashleymills 0:e979170e02e7 906 if (mp_cmp (&u, &v) != MP_LT) {
ashleymills 0:e979170e02e7 907 /* u = u - v, B = B - D */
ashleymills 0:e979170e02e7 908 if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
ashleymills 0:e979170e02e7 909 goto LBL_ERR;
ashleymills 0:e979170e02e7 910 }
ashleymills 0:e979170e02e7 911
ashleymills 0:e979170e02e7 912 if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
ashleymills 0:e979170e02e7 913 goto LBL_ERR;
ashleymills 0:e979170e02e7 914 }
ashleymills 0:e979170e02e7 915 } else {
ashleymills 0:e979170e02e7 916 /* v - v - u, D = D - B */
ashleymills 0:e979170e02e7 917 if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
ashleymills 0:e979170e02e7 918 goto LBL_ERR;
ashleymills 0:e979170e02e7 919 }
ashleymills 0:e979170e02e7 920
ashleymills 0:e979170e02e7 921 if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
ashleymills 0:e979170e02e7 922 goto LBL_ERR;
ashleymills 0:e979170e02e7 923 }
ashleymills 0:e979170e02e7 924 }
ashleymills 0:e979170e02e7 925
ashleymills 0:e979170e02e7 926 /* if not zero goto step 4 */
ashleymills 0:e979170e02e7 927 if (mp_iszero (&u) == 0) {
ashleymills 0:e979170e02e7 928 goto top;
ashleymills 0:e979170e02e7 929 }
ashleymills 0:e979170e02e7 930
ashleymills 0:e979170e02e7 931 /* now a = C, b = D, gcd == g*v */
ashleymills 0:e979170e02e7 932
ashleymills 0:e979170e02e7 933 /* if v != 1 then there is no inverse */
ashleymills 0:e979170e02e7 934 if (mp_cmp_d (&v, 1) != MP_EQ) {
ashleymills 0:e979170e02e7 935 res = MP_VAL;
ashleymills 0:e979170e02e7 936 goto LBL_ERR;
ashleymills 0:e979170e02e7 937 }
ashleymills 0:e979170e02e7 938
ashleymills 0:e979170e02e7 939 /* b is now the inverse */
ashleymills 0:e979170e02e7 940 neg = a->sign;
ashleymills 0:e979170e02e7 941 while (D.sign == MP_NEG) {
ashleymills 0:e979170e02e7 942 if ((res = mp_add (&D, b, &D)) != MP_OKAY) {
ashleymills 0:e979170e02e7 943 goto LBL_ERR;
ashleymills 0:e979170e02e7 944 }
ashleymills 0:e979170e02e7 945 }
ashleymills 0:e979170e02e7 946 mp_exch (&D, c);
ashleymills 0:e979170e02e7 947 c->sign = neg;
ashleymills 0:e979170e02e7 948 res = MP_OKAY;
ashleymills 0:e979170e02e7 949
ashleymills 0:e979170e02e7 950 LBL_ERR:mp_clear(&x);
ashleymills 0:e979170e02e7 951 mp_clear(&y);
ashleymills 0:e979170e02e7 952 mp_clear(&u);
ashleymills 0:e979170e02e7 953 mp_clear(&v);
ashleymills 0:e979170e02e7 954 mp_clear(&B);
ashleymills 0:e979170e02e7 955 mp_clear(&D);
ashleymills 0:e979170e02e7 956 return res;
ashleymills 0:e979170e02e7 957 }
ashleymills 0:e979170e02e7 958
ashleymills 0:e979170e02e7 959
ashleymills 0:e979170e02e7 960 /* hac 14.61, pp608 */
ashleymills 0:e979170e02e7 961 int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
ashleymills 0:e979170e02e7 962 {
ashleymills 0:e979170e02e7 963 mp_int x, y, u, v, A, B, C, D;
ashleymills 0:e979170e02e7 964 int res;
ashleymills 0:e979170e02e7 965
ashleymills 0:e979170e02e7 966 /* b cannot be negative */
ashleymills 0:e979170e02e7 967 if (b->sign == MP_NEG || mp_iszero(b) == 1) {
ashleymills 0:e979170e02e7 968 return MP_VAL;
ashleymills 0:e979170e02e7 969 }
ashleymills 0:e979170e02e7 970
ashleymills 0:e979170e02e7 971 /* init temps */
ashleymills 0:e979170e02e7 972 if ((res = mp_init_multi(&x, &y, &u, &v,
ashleymills 0:e979170e02e7 973 &A, &B)) != MP_OKAY) {
ashleymills 0:e979170e02e7 974 return res;
ashleymills 0:e979170e02e7 975 }
ashleymills 0:e979170e02e7 976
ashleymills 0:e979170e02e7 977 /* init rest of tmps temps */
ashleymills 0:e979170e02e7 978 if ((res = mp_init_multi(&C, &D, 0, 0, 0, 0)) != MP_OKAY) {
ashleymills 0:e979170e02e7 979 return res;
ashleymills 0:e979170e02e7 980 }
ashleymills 0:e979170e02e7 981
ashleymills 0:e979170e02e7 982 /* x = a, y = b */
ashleymills 0:e979170e02e7 983 if ((res = mp_mod(a, b, &x)) != MP_OKAY) {
ashleymills 0:e979170e02e7 984 goto LBL_ERR;
ashleymills 0:e979170e02e7 985 }
ashleymills 0:e979170e02e7 986 if ((res = mp_copy (b, &y)) != MP_OKAY) {
ashleymills 0:e979170e02e7 987 goto LBL_ERR;
ashleymills 0:e979170e02e7 988 }
ashleymills 0:e979170e02e7 989
ashleymills 0:e979170e02e7 990 /* 2. [modified] if x,y are both even then return an error! */
ashleymills 0:e979170e02e7 991 if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) {
ashleymills 0:e979170e02e7 992 res = MP_VAL;
ashleymills 0:e979170e02e7 993 goto LBL_ERR;
ashleymills 0:e979170e02e7 994 }
ashleymills 0:e979170e02e7 995
ashleymills 0:e979170e02e7 996 /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
ashleymills 0:e979170e02e7 997 if ((res = mp_copy (&x, &u)) != MP_OKAY) {
ashleymills 0:e979170e02e7 998 goto LBL_ERR;
ashleymills 0:e979170e02e7 999 }
ashleymills 0:e979170e02e7 1000 if ((res = mp_copy (&y, &v)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1001 goto LBL_ERR;
ashleymills 0:e979170e02e7 1002 }
ashleymills 0:e979170e02e7 1003 mp_set (&A, 1);
ashleymills 0:e979170e02e7 1004 mp_set (&D, 1);
ashleymills 0:e979170e02e7 1005
ashleymills 0:e979170e02e7 1006 top:
ashleymills 0:e979170e02e7 1007 /* 4. while u is even do */
ashleymills 0:e979170e02e7 1008 while (mp_iseven (&u) == 1) {
ashleymills 0:e979170e02e7 1009 /* 4.1 u = u/2 */
ashleymills 0:e979170e02e7 1010 if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1011 goto LBL_ERR;
ashleymills 0:e979170e02e7 1012 }
ashleymills 0:e979170e02e7 1013 /* 4.2 if A or B is odd then */
ashleymills 0:e979170e02e7 1014 if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) {
ashleymills 0:e979170e02e7 1015 /* A = (A+y)/2, B = (B-x)/2 */
ashleymills 0:e979170e02e7 1016 if ((res = mp_add (&A, &y, &A)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1017 goto LBL_ERR;
ashleymills 0:e979170e02e7 1018 }
ashleymills 0:e979170e02e7 1019 if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1020 goto LBL_ERR;
ashleymills 0:e979170e02e7 1021 }
ashleymills 0:e979170e02e7 1022 }
ashleymills 0:e979170e02e7 1023 /* A = A/2, B = B/2 */
ashleymills 0:e979170e02e7 1024 if ((res = mp_div_2 (&A, &A)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1025 goto LBL_ERR;
ashleymills 0:e979170e02e7 1026 }
ashleymills 0:e979170e02e7 1027 if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1028 goto LBL_ERR;
ashleymills 0:e979170e02e7 1029 }
ashleymills 0:e979170e02e7 1030 }
ashleymills 0:e979170e02e7 1031
ashleymills 0:e979170e02e7 1032 /* 5. while v is even do */
ashleymills 0:e979170e02e7 1033 while (mp_iseven (&v) == 1) {
ashleymills 0:e979170e02e7 1034 /* 5.1 v = v/2 */
ashleymills 0:e979170e02e7 1035 if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1036 goto LBL_ERR;
ashleymills 0:e979170e02e7 1037 }
ashleymills 0:e979170e02e7 1038 /* 5.2 if C or D is odd then */
ashleymills 0:e979170e02e7 1039 if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) {
ashleymills 0:e979170e02e7 1040 /* C = (C+y)/2, D = (D-x)/2 */
ashleymills 0:e979170e02e7 1041 if ((res = mp_add (&C, &y, &C)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1042 goto LBL_ERR;
ashleymills 0:e979170e02e7 1043 }
ashleymills 0:e979170e02e7 1044 if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1045 goto LBL_ERR;
ashleymills 0:e979170e02e7 1046 }
ashleymills 0:e979170e02e7 1047 }
ashleymills 0:e979170e02e7 1048 /* C = C/2, D = D/2 */
ashleymills 0:e979170e02e7 1049 if ((res = mp_div_2 (&C, &C)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1050 goto LBL_ERR;
ashleymills 0:e979170e02e7 1051 }
ashleymills 0:e979170e02e7 1052 if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1053 goto LBL_ERR;
ashleymills 0:e979170e02e7 1054 }
ashleymills 0:e979170e02e7 1055 }
ashleymills 0:e979170e02e7 1056
ashleymills 0:e979170e02e7 1057 /* 6. if u >= v then */
ashleymills 0:e979170e02e7 1058 if (mp_cmp (&u, &v) != MP_LT) {
ashleymills 0:e979170e02e7 1059 /* u = u - v, A = A - C, B = B - D */
ashleymills 0:e979170e02e7 1060 if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1061 goto LBL_ERR;
ashleymills 0:e979170e02e7 1062 }
ashleymills 0:e979170e02e7 1063
ashleymills 0:e979170e02e7 1064 if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1065 goto LBL_ERR;
ashleymills 0:e979170e02e7 1066 }
ashleymills 0:e979170e02e7 1067
ashleymills 0:e979170e02e7 1068 if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1069 goto LBL_ERR;
ashleymills 0:e979170e02e7 1070 }
ashleymills 0:e979170e02e7 1071 } else {
ashleymills 0:e979170e02e7 1072 /* v - v - u, C = C - A, D = D - B */
ashleymills 0:e979170e02e7 1073 if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1074 goto LBL_ERR;
ashleymills 0:e979170e02e7 1075 }
ashleymills 0:e979170e02e7 1076
ashleymills 0:e979170e02e7 1077 if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1078 goto LBL_ERR;
ashleymills 0:e979170e02e7 1079 }
ashleymills 0:e979170e02e7 1080
ashleymills 0:e979170e02e7 1081 if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1082 goto LBL_ERR;
ashleymills 0:e979170e02e7 1083 }
ashleymills 0:e979170e02e7 1084 }
ashleymills 0:e979170e02e7 1085
ashleymills 0:e979170e02e7 1086 /* if not zero goto step 4 */
ashleymills 0:e979170e02e7 1087 if (mp_iszero (&u) == 0)
ashleymills 0:e979170e02e7 1088 goto top;
ashleymills 0:e979170e02e7 1089
ashleymills 0:e979170e02e7 1090 /* now a = C, b = D, gcd == g*v */
ashleymills 0:e979170e02e7 1091
ashleymills 0:e979170e02e7 1092 /* if v != 1 then there is no inverse */
ashleymills 0:e979170e02e7 1093 if (mp_cmp_d (&v, 1) != MP_EQ) {
ashleymills 0:e979170e02e7 1094 res = MP_VAL;
ashleymills 0:e979170e02e7 1095 goto LBL_ERR;
ashleymills 0:e979170e02e7 1096 }
ashleymills 0:e979170e02e7 1097
ashleymills 0:e979170e02e7 1098 /* if its too low */
ashleymills 0:e979170e02e7 1099 while (mp_cmp_d(&C, 0) == MP_LT) {
ashleymills 0:e979170e02e7 1100 if ((res = mp_add(&C, b, &C)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1101 goto LBL_ERR;
ashleymills 0:e979170e02e7 1102 }
ashleymills 0:e979170e02e7 1103 }
ashleymills 0:e979170e02e7 1104
ashleymills 0:e979170e02e7 1105 /* too big */
ashleymills 0:e979170e02e7 1106 while (mp_cmp_mag(&C, b) != MP_LT) {
ashleymills 0:e979170e02e7 1107 if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1108 goto LBL_ERR;
ashleymills 0:e979170e02e7 1109 }
ashleymills 0:e979170e02e7 1110 }
ashleymills 0:e979170e02e7 1111
ashleymills 0:e979170e02e7 1112 /* C is now the inverse */
ashleymills 0:e979170e02e7 1113 mp_exch (&C, c);
ashleymills 0:e979170e02e7 1114 res = MP_OKAY;
ashleymills 0:e979170e02e7 1115 LBL_ERR:mp_clear(&x);
ashleymills 0:e979170e02e7 1116 mp_clear(&y);
ashleymills 0:e979170e02e7 1117 mp_clear(&u);
ashleymills 0:e979170e02e7 1118 mp_clear(&v);
ashleymills 0:e979170e02e7 1119 mp_clear(&A);
ashleymills 0:e979170e02e7 1120 mp_clear(&B);
ashleymills 0:e979170e02e7 1121 mp_clear(&C);
ashleymills 0:e979170e02e7 1122 mp_clear(&D);
ashleymills 0:e979170e02e7 1123 return res;
ashleymills 0:e979170e02e7 1124 }
ashleymills 0:e979170e02e7 1125
ashleymills 0:e979170e02e7 1126
ashleymills 0:e979170e02e7 1127 /* compare maginitude of two ints (unsigned) */
ashleymills 0:e979170e02e7 1128 int mp_cmp_mag (mp_int * a, mp_int * b)
ashleymills 0:e979170e02e7 1129 {
ashleymills 0:e979170e02e7 1130 int n;
ashleymills 0:e979170e02e7 1131 mp_digit *tmpa, *tmpb;
ashleymills 0:e979170e02e7 1132
ashleymills 0:e979170e02e7 1133 /* compare based on # of non-zero digits */
ashleymills 0:e979170e02e7 1134 if (a->used > b->used) {
ashleymills 0:e979170e02e7 1135 return MP_GT;
ashleymills 0:e979170e02e7 1136 }
ashleymills 0:e979170e02e7 1137
ashleymills 0:e979170e02e7 1138 if (a->used < b->used) {
ashleymills 0:e979170e02e7 1139 return MP_LT;
ashleymills 0:e979170e02e7 1140 }
ashleymills 0:e979170e02e7 1141
ashleymills 0:e979170e02e7 1142 /* alias for a */
ashleymills 0:e979170e02e7 1143 tmpa = a->dp + (a->used - 1);
ashleymills 0:e979170e02e7 1144
ashleymills 0:e979170e02e7 1145 /* alias for b */
ashleymills 0:e979170e02e7 1146 tmpb = b->dp + (a->used - 1);
ashleymills 0:e979170e02e7 1147
ashleymills 0:e979170e02e7 1148 /* compare based on digits */
ashleymills 0:e979170e02e7 1149 for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
ashleymills 0:e979170e02e7 1150 if (*tmpa > *tmpb) {
ashleymills 0:e979170e02e7 1151 return MP_GT;
ashleymills 0:e979170e02e7 1152 }
ashleymills 0:e979170e02e7 1153
ashleymills 0:e979170e02e7 1154 if (*tmpa < *tmpb) {
ashleymills 0:e979170e02e7 1155 return MP_LT;
ashleymills 0:e979170e02e7 1156 }
ashleymills 0:e979170e02e7 1157 }
ashleymills 0:e979170e02e7 1158 return MP_EQ;
ashleymills 0:e979170e02e7 1159 }
ashleymills 0:e979170e02e7 1160
ashleymills 0:e979170e02e7 1161
ashleymills 0:e979170e02e7 1162 /* compare two ints (signed)*/
ashleymills 0:e979170e02e7 1163 int
ashleymills 0:e979170e02e7 1164 mp_cmp (mp_int * a, mp_int * b)
ashleymills 0:e979170e02e7 1165 {
ashleymills 0:e979170e02e7 1166 /* compare based on sign */
ashleymills 0:e979170e02e7 1167 if (a->sign != b->sign) {
ashleymills 0:e979170e02e7 1168 if (a->sign == MP_NEG) {
ashleymills 0:e979170e02e7 1169 return MP_LT;
ashleymills 0:e979170e02e7 1170 } else {
ashleymills 0:e979170e02e7 1171 return MP_GT;
ashleymills 0:e979170e02e7 1172 }
ashleymills 0:e979170e02e7 1173 }
ashleymills 0:e979170e02e7 1174
ashleymills 0:e979170e02e7 1175 /* compare digits */
ashleymills 0:e979170e02e7 1176 if (a->sign == MP_NEG) {
ashleymills 0:e979170e02e7 1177 /* if negative compare opposite direction */
ashleymills 0:e979170e02e7 1178 return mp_cmp_mag(b, a);
ashleymills 0:e979170e02e7 1179 } else {
ashleymills 0:e979170e02e7 1180 return mp_cmp_mag(a, b);
ashleymills 0:e979170e02e7 1181 }
ashleymills 0:e979170e02e7 1182 }
ashleymills 0:e979170e02e7 1183
ashleymills 0:e979170e02e7 1184
ashleymills 0:e979170e02e7 1185 /* compare a digit */
ashleymills 0:e979170e02e7 1186 int mp_cmp_d(mp_int * a, mp_digit b)
ashleymills 0:e979170e02e7 1187 {
ashleymills 0:e979170e02e7 1188 /* compare based on sign */
ashleymills 0:e979170e02e7 1189 if (a->sign == MP_NEG) {
ashleymills 0:e979170e02e7 1190 return MP_LT;
ashleymills 0:e979170e02e7 1191 }
ashleymills 0:e979170e02e7 1192
ashleymills 0:e979170e02e7 1193 /* compare based on magnitude */
ashleymills 0:e979170e02e7 1194 if (a->used > 1) {
ashleymills 0:e979170e02e7 1195 return MP_GT;
ashleymills 0:e979170e02e7 1196 }
ashleymills 0:e979170e02e7 1197
ashleymills 0:e979170e02e7 1198 /* compare the only digit of a to b */
ashleymills 0:e979170e02e7 1199 if (a->dp[0] > b) {
ashleymills 0:e979170e02e7 1200 return MP_GT;
ashleymills 0:e979170e02e7 1201 } else if (a->dp[0] < b) {
ashleymills 0:e979170e02e7 1202 return MP_LT;
ashleymills 0:e979170e02e7 1203 } else {
ashleymills 0:e979170e02e7 1204 return MP_EQ;
ashleymills 0:e979170e02e7 1205 }
ashleymills 0:e979170e02e7 1206 }
ashleymills 0:e979170e02e7 1207
ashleymills 0:e979170e02e7 1208
ashleymills 0:e979170e02e7 1209 /* set to a digit */
ashleymills 0:e979170e02e7 1210 void mp_set (mp_int * a, mp_digit b)
ashleymills 0:e979170e02e7 1211 {
ashleymills 0:e979170e02e7 1212 mp_zero (a);
ashleymills 0:e979170e02e7 1213 a->dp[0] = b & MP_MASK;
ashleymills 0:e979170e02e7 1214 a->used = (a->dp[0] != 0) ? 1 : 0;
ashleymills 0:e979170e02e7 1215 }
ashleymills 0:e979170e02e7 1216
ashleymills 0:e979170e02e7 1217
ashleymills 0:e979170e02e7 1218 /* c = a mod b, 0 <= c < b */
ashleymills 0:e979170e02e7 1219 int
ashleymills 0:e979170e02e7 1220 mp_mod (mp_int * a, mp_int * b, mp_int * c)
ashleymills 0:e979170e02e7 1221 {
ashleymills 0:e979170e02e7 1222 mp_int t;
ashleymills 0:e979170e02e7 1223 int res;
ashleymills 0:e979170e02e7 1224
ashleymills 0:e979170e02e7 1225 if ((res = mp_init (&t)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1226 return res;
ashleymills 0:e979170e02e7 1227 }
ashleymills 0:e979170e02e7 1228
ashleymills 0:e979170e02e7 1229 if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1230 mp_clear (&t);
ashleymills 0:e979170e02e7 1231 return res;
ashleymills 0:e979170e02e7 1232 }
ashleymills 0:e979170e02e7 1233
ashleymills 0:e979170e02e7 1234 if (t.sign != b->sign) {
ashleymills 0:e979170e02e7 1235 res = mp_add (b, &t, c);
ashleymills 0:e979170e02e7 1236 } else {
ashleymills 0:e979170e02e7 1237 res = MP_OKAY;
ashleymills 0:e979170e02e7 1238 mp_exch (&t, c);
ashleymills 0:e979170e02e7 1239 }
ashleymills 0:e979170e02e7 1240
ashleymills 0:e979170e02e7 1241 mp_clear (&t);
ashleymills 0:e979170e02e7 1242 return res;
ashleymills 0:e979170e02e7 1243 }
ashleymills 0:e979170e02e7 1244
ashleymills 0:e979170e02e7 1245
ashleymills 0:e979170e02e7 1246 /* slower bit-bang division... also smaller */
ashleymills 0:e979170e02e7 1247 int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
ashleymills 0:e979170e02e7 1248 {
ashleymills 0:e979170e02e7 1249 mp_int ta, tb, tq, q;
ashleymills 0:e979170e02e7 1250 int res, n, n2;
ashleymills 0:e979170e02e7 1251
ashleymills 0:e979170e02e7 1252 /* is divisor zero ? */
ashleymills 0:e979170e02e7 1253 if (mp_iszero (b) == 1) {
ashleymills 0:e979170e02e7 1254 return MP_VAL;
ashleymills 0:e979170e02e7 1255 }
ashleymills 0:e979170e02e7 1256
ashleymills 0:e979170e02e7 1257 /* if a < b then q=0, r = a */
ashleymills 0:e979170e02e7 1258 if (mp_cmp_mag (a, b) == MP_LT) {
ashleymills 0:e979170e02e7 1259 if (d != NULL) {
ashleymills 0:e979170e02e7 1260 res = mp_copy (a, d);
ashleymills 0:e979170e02e7 1261 } else {
ashleymills 0:e979170e02e7 1262 res = MP_OKAY;
ashleymills 0:e979170e02e7 1263 }
ashleymills 0:e979170e02e7 1264 if (c != NULL) {
ashleymills 0:e979170e02e7 1265 mp_zero (c);
ashleymills 0:e979170e02e7 1266 }
ashleymills 0:e979170e02e7 1267 return res;
ashleymills 0:e979170e02e7 1268 }
ashleymills 0:e979170e02e7 1269
ashleymills 0:e979170e02e7 1270 /* init our temps */
ashleymills 0:e979170e02e7 1271 if ((res = mp_init_multi(&ta, &tb, &tq, &q, 0, 0)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1272 return res;
ashleymills 0:e979170e02e7 1273 }
ashleymills 0:e979170e02e7 1274
ashleymills 0:e979170e02e7 1275
ashleymills 0:e979170e02e7 1276 mp_set(&tq, 1);
ashleymills 0:e979170e02e7 1277 n = mp_count_bits(a) - mp_count_bits(b);
ashleymills 0:e979170e02e7 1278 if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
ashleymills 0:e979170e02e7 1279 ((res = mp_abs(b, &tb)) != MP_OKAY) ||
ashleymills 0:e979170e02e7 1280 ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
ashleymills 0:e979170e02e7 1281 ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
ashleymills 0:e979170e02e7 1282 goto LBL_ERR;
ashleymills 0:e979170e02e7 1283 }
ashleymills 0:e979170e02e7 1284
ashleymills 0:e979170e02e7 1285 while (n-- >= 0) {
ashleymills 0:e979170e02e7 1286 if (mp_cmp(&tb, &ta) != MP_GT) {
ashleymills 0:e979170e02e7 1287 if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) ||
ashleymills 0:e979170e02e7 1288 ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) {
ashleymills 0:e979170e02e7 1289 goto LBL_ERR;
ashleymills 0:e979170e02e7 1290 }
ashleymills 0:e979170e02e7 1291 }
ashleymills 0:e979170e02e7 1292 if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) ||
ashleymills 0:e979170e02e7 1293 ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) {
ashleymills 0:e979170e02e7 1294 goto LBL_ERR;
ashleymills 0:e979170e02e7 1295 }
ashleymills 0:e979170e02e7 1296 }
ashleymills 0:e979170e02e7 1297
ashleymills 0:e979170e02e7 1298 /* now q == quotient and ta == remainder */
ashleymills 0:e979170e02e7 1299 n = a->sign;
ashleymills 0:e979170e02e7 1300 n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG);
ashleymills 0:e979170e02e7 1301 if (c != NULL) {
ashleymills 0:e979170e02e7 1302 mp_exch(c, &q);
ashleymills 0:e979170e02e7 1303 c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2;
ashleymills 0:e979170e02e7 1304 }
ashleymills 0:e979170e02e7 1305 if (d != NULL) {
ashleymills 0:e979170e02e7 1306 mp_exch(d, &ta);
ashleymills 0:e979170e02e7 1307 d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n;
ashleymills 0:e979170e02e7 1308 }
ashleymills 0:e979170e02e7 1309 LBL_ERR:
ashleymills 0:e979170e02e7 1310 mp_clear(&ta);
ashleymills 0:e979170e02e7 1311 mp_clear(&tb);
ashleymills 0:e979170e02e7 1312 mp_clear(&tq);
ashleymills 0:e979170e02e7 1313 mp_clear(&q);
ashleymills 0:e979170e02e7 1314 return res;
ashleymills 0:e979170e02e7 1315 }
ashleymills 0:e979170e02e7 1316
ashleymills 0:e979170e02e7 1317
ashleymills 0:e979170e02e7 1318 /* b = a/2 */
ashleymills 0:e979170e02e7 1319 int mp_div_2(mp_int * a, mp_int * b)
ashleymills 0:e979170e02e7 1320 {
ashleymills 0:e979170e02e7 1321 int x, res, oldused;
ashleymills 0:e979170e02e7 1322
ashleymills 0:e979170e02e7 1323 /* copy */
ashleymills 0:e979170e02e7 1324 if (b->alloc < a->used) {
ashleymills 0:e979170e02e7 1325 if ((res = mp_grow (b, a->used)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1326 return res;
ashleymills 0:e979170e02e7 1327 }
ashleymills 0:e979170e02e7 1328 }
ashleymills 0:e979170e02e7 1329
ashleymills 0:e979170e02e7 1330 oldused = b->used;
ashleymills 0:e979170e02e7 1331 b->used = a->used;
ashleymills 0:e979170e02e7 1332 {
ashleymills 0:e979170e02e7 1333 register mp_digit r, rr, *tmpa, *tmpb;
ashleymills 0:e979170e02e7 1334
ashleymills 0:e979170e02e7 1335 /* source alias */
ashleymills 0:e979170e02e7 1336 tmpa = a->dp + b->used - 1;
ashleymills 0:e979170e02e7 1337
ashleymills 0:e979170e02e7 1338 /* dest alias */
ashleymills 0:e979170e02e7 1339 tmpb = b->dp + b->used - 1;
ashleymills 0:e979170e02e7 1340
ashleymills 0:e979170e02e7 1341 /* carry */
ashleymills 0:e979170e02e7 1342 r = 0;
ashleymills 0:e979170e02e7 1343 for (x = b->used - 1; x >= 0; x--) {
ashleymills 0:e979170e02e7 1344 /* get the carry for the next iteration */
ashleymills 0:e979170e02e7 1345 rr = *tmpa & 1;
ashleymills 0:e979170e02e7 1346
ashleymills 0:e979170e02e7 1347 /* shift the current digit, add in carry and store */
ashleymills 0:e979170e02e7 1348 *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
ashleymills 0:e979170e02e7 1349
ashleymills 0:e979170e02e7 1350 /* forward carry to next iteration */
ashleymills 0:e979170e02e7 1351 r = rr;
ashleymills 0:e979170e02e7 1352 }
ashleymills 0:e979170e02e7 1353
ashleymills 0:e979170e02e7 1354 /* zero excess digits */
ashleymills 0:e979170e02e7 1355 tmpb = b->dp + b->used;
ashleymills 0:e979170e02e7 1356 for (x = b->used; x < oldused; x++) {
ashleymills 0:e979170e02e7 1357 *tmpb++ = 0;
ashleymills 0:e979170e02e7 1358 }
ashleymills 0:e979170e02e7 1359 }
ashleymills 0:e979170e02e7 1360 b->sign = a->sign;
ashleymills 0:e979170e02e7 1361 mp_clamp (b);
ashleymills 0:e979170e02e7 1362 return MP_OKAY;
ashleymills 0:e979170e02e7 1363 }
ashleymills 0:e979170e02e7 1364
ashleymills 0:e979170e02e7 1365
ashleymills 0:e979170e02e7 1366 /* high level addition (handles signs) */
ashleymills 0:e979170e02e7 1367 int mp_add (mp_int * a, mp_int * b, mp_int * c)
ashleymills 0:e979170e02e7 1368 {
ashleymills 0:e979170e02e7 1369 int sa, sb, res;
ashleymills 0:e979170e02e7 1370
ashleymills 0:e979170e02e7 1371 /* get sign of both inputs */
ashleymills 0:e979170e02e7 1372 sa = a->sign;
ashleymills 0:e979170e02e7 1373 sb = b->sign;
ashleymills 0:e979170e02e7 1374
ashleymills 0:e979170e02e7 1375 /* handle two cases, not four */
ashleymills 0:e979170e02e7 1376 if (sa == sb) {
ashleymills 0:e979170e02e7 1377 /* both positive or both negative */
ashleymills 0:e979170e02e7 1378 /* add their magnitudes, copy the sign */
ashleymills 0:e979170e02e7 1379 c->sign = sa;
ashleymills 0:e979170e02e7 1380 res = s_mp_add (a, b, c);
ashleymills 0:e979170e02e7 1381 } else {
ashleymills 0:e979170e02e7 1382 /* one positive, the other negative */
ashleymills 0:e979170e02e7 1383 /* subtract the one with the greater magnitude from */
ashleymills 0:e979170e02e7 1384 /* the one of the lesser magnitude. The result gets */
ashleymills 0:e979170e02e7 1385 /* the sign of the one with the greater magnitude. */
ashleymills 0:e979170e02e7 1386 if (mp_cmp_mag (a, b) == MP_LT) {
ashleymills 0:e979170e02e7 1387 c->sign = sb;
ashleymills 0:e979170e02e7 1388 res = s_mp_sub (b, a, c);
ashleymills 0:e979170e02e7 1389 } else {
ashleymills 0:e979170e02e7 1390 c->sign = sa;
ashleymills 0:e979170e02e7 1391 res = s_mp_sub (a, b, c);
ashleymills 0:e979170e02e7 1392 }
ashleymills 0:e979170e02e7 1393 }
ashleymills 0:e979170e02e7 1394 return res;
ashleymills 0:e979170e02e7 1395 }
ashleymills 0:e979170e02e7 1396
ashleymills 0:e979170e02e7 1397
ashleymills 0:e979170e02e7 1398 /* low level addition, based on HAC pp.594, Algorithm 14.7 */
ashleymills 0:e979170e02e7 1399 int
ashleymills 0:e979170e02e7 1400 s_mp_add (mp_int * a, mp_int * b, mp_int * c)
ashleymills 0:e979170e02e7 1401 {
ashleymills 0:e979170e02e7 1402 mp_int *x;
ashleymills 0:e979170e02e7 1403 int olduse, res, min, max;
ashleymills 0:e979170e02e7 1404
ashleymills 0:e979170e02e7 1405 /* find sizes, we let |a| <= |b| which means we have to sort
ashleymills 0:e979170e02e7 1406 * them. "x" will point to the input with the most digits
ashleymills 0:e979170e02e7 1407 */
ashleymills 0:e979170e02e7 1408 if (a->used > b->used) {
ashleymills 0:e979170e02e7 1409 min = b->used;
ashleymills 0:e979170e02e7 1410 max = a->used;
ashleymills 0:e979170e02e7 1411 x = a;
ashleymills 0:e979170e02e7 1412 } else {
ashleymills 0:e979170e02e7 1413 min = a->used;
ashleymills 0:e979170e02e7 1414 max = b->used;
ashleymills 0:e979170e02e7 1415 x = b;
ashleymills 0:e979170e02e7 1416 }
ashleymills 0:e979170e02e7 1417
ashleymills 0:e979170e02e7 1418 /* init result */
ashleymills 0:e979170e02e7 1419 if (c->alloc < max + 1) {
ashleymills 0:e979170e02e7 1420 if ((res = mp_grow (c, max + 1)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1421 return res;
ashleymills 0:e979170e02e7 1422 }
ashleymills 0:e979170e02e7 1423 }
ashleymills 0:e979170e02e7 1424
ashleymills 0:e979170e02e7 1425 /* get old used digit count and set new one */
ashleymills 0:e979170e02e7 1426 olduse = c->used;
ashleymills 0:e979170e02e7 1427 c->used = max + 1;
ashleymills 0:e979170e02e7 1428
ashleymills 0:e979170e02e7 1429 {
ashleymills 0:e979170e02e7 1430 register mp_digit u, *tmpa, *tmpb, *tmpc;
ashleymills 0:e979170e02e7 1431 register int i;
ashleymills 0:e979170e02e7 1432
ashleymills 0:e979170e02e7 1433 /* alias for digit pointers */
ashleymills 0:e979170e02e7 1434
ashleymills 0:e979170e02e7 1435 /* first input */
ashleymills 0:e979170e02e7 1436 tmpa = a->dp;
ashleymills 0:e979170e02e7 1437
ashleymills 0:e979170e02e7 1438 /* second input */
ashleymills 0:e979170e02e7 1439 tmpb = b->dp;
ashleymills 0:e979170e02e7 1440
ashleymills 0:e979170e02e7 1441 /* destination */
ashleymills 0:e979170e02e7 1442 tmpc = c->dp;
ashleymills 0:e979170e02e7 1443
ashleymills 0:e979170e02e7 1444 /* zero the carry */
ashleymills 0:e979170e02e7 1445 u = 0;
ashleymills 0:e979170e02e7 1446 for (i = 0; i < min; i++) {
ashleymills 0:e979170e02e7 1447 /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */
ashleymills 0:e979170e02e7 1448 *tmpc = *tmpa++ + *tmpb++ + u;
ashleymills 0:e979170e02e7 1449
ashleymills 0:e979170e02e7 1450 /* U = carry bit of T[i] */
ashleymills 0:e979170e02e7 1451 u = *tmpc >> ((mp_digit)DIGIT_BIT);
ashleymills 0:e979170e02e7 1452
ashleymills 0:e979170e02e7 1453 /* take away carry bit from T[i] */
ashleymills 0:e979170e02e7 1454 *tmpc++ &= MP_MASK;
ashleymills 0:e979170e02e7 1455 }
ashleymills 0:e979170e02e7 1456
ashleymills 0:e979170e02e7 1457 /* now copy higher words if any, that is in A+B
ashleymills 0:e979170e02e7 1458 * if A or B has more digits add those in
ashleymills 0:e979170e02e7 1459 */
ashleymills 0:e979170e02e7 1460 if (min != max) {
ashleymills 0:e979170e02e7 1461 for (; i < max; i++) {
ashleymills 0:e979170e02e7 1462 /* T[i] = X[i] + U */
ashleymills 0:e979170e02e7 1463 *tmpc = x->dp[i] + u;
ashleymills 0:e979170e02e7 1464
ashleymills 0:e979170e02e7 1465 /* U = carry bit of T[i] */
ashleymills 0:e979170e02e7 1466 u = *tmpc >> ((mp_digit)DIGIT_BIT);
ashleymills 0:e979170e02e7 1467
ashleymills 0:e979170e02e7 1468 /* take away carry bit from T[i] */
ashleymills 0:e979170e02e7 1469 *tmpc++ &= MP_MASK;
ashleymills 0:e979170e02e7 1470 }
ashleymills 0:e979170e02e7 1471 }
ashleymills 0:e979170e02e7 1472
ashleymills 0:e979170e02e7 1473 /* add carry */
ashleymills 0:e979170e02e7 1474 *tmpc++ = u;
ashleymills 0:e979170e02e7 1475
ashleymills 0:e979170e02e7 1476 /* clear digits above oldused */
ashleymills 0:e979170e02e7 1477 for (i = c->used; i < olduse; i++) {
ashleymills 0:e979170e02e7 1478 *tmpc++ = 0;
ashleymills 0:e979170e02e7 1479 }
ashleymills 0:e979170e02e7 1480 }
ashleymills 0:e979170e02e7 1481
ashleymills 0:e979170e02e7 1482 mp_clamp (c);
ashleymills 0:e979170e02e7 1483 return MP_OKAY;
ashleymills 0:e979170e02e7 1484 }
ashleymills 0:e979170e02e7 1485
ashleymills 0:e979170e02e7 1486
ashleymills 0:e979170e02e7 1487 /* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
ashleymills 0:e979170e02e7 1488 int
ashleymills 0:e979170e02e7 1489 s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
ashleymills 0:e979170e02e7 1490 {
ashleymills 0:e979170e02e7 1491 int olduse, res, min, max;
ashleymills 0:e979170e02e7 1492
ashleymills 0:e979170e02e7 1493 /* find sizes */
ashleymills 0:e979170e02e7 1494 min = b->used;
ashleymills 0:e979170e02e7 1495 max = a->used;
ashleymills 0:e979170e02e7 1496
ashleymills 0:e979170e02e7 1497 /* init result */
ashleymills 0:e979170e02e7 1498 if (c->alloc < max) {
ashleymills 0:e979170e02e7 1499 if ((res = mp_grow (c, max)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1500 return res;
ashleymills 0:e979170e02e7 1501 }
ashleymills 0:e979170e02e7 1502 }
ashleymills 0:e979170e02e7 1503 olduse = c->used;
ashleymills 0:e979170e02e7 1504 c->used = max;
ashleymills 0:e979170e02e7 1505
ashleymills 0:e979170e02e7 1506 {
ashleymills 0:e979170e02e7 1507 register mp_digit u, *tmpa, *tmpb, *tmpc;
ashleymills 0:e979170e02e7 1508 register int i;
ashleymills 0:e979170e02e7 1509
ashleymills 0:e979170e02e7 1510 /* alias for digit pointers */
ashleymills 0:e979170e02e7 1511 tmpa = a->dp;
ashleymills 0:e979170e02e7 1512 tmpb = b->dp;
ashleymills 0:e979170e02e7 1513 tmpc = c->dp;
ashleymills 0:e979170e02e7 1514
ashleymills 0:e979170e02e7 1515 /* set carry to zero */
ashleymills 0:e979170e02e7 1516 u = 0;
ashleymills 0:e979170e02e7 1517 for (i = 0; i < min; i++) {
ashleymills 0:e979170e02e7 1518 /* T[i] = A[i] - B[i] - U */
ashleymills 0:e979170e02e7 1519 *tmpc = *tmpa++ - *tmpb++ - u;
ashleymills 0:e979170e02e7 1520
ashleymills 0:e979170e02e7 1521 /* U = carry bit of T[i]
ashleymills 0:e979170e02e7 1522 * Note this saves performing an AND operation since
ashleymills 0:e979170e02e7 1523 * if a carry does occur it will propagate all the way to the
ashleymills 0:e979170e02e7 1524 * MSB. As a result a single shift is enough to get the carry
ashleymills 0:e979170e02e7 1525 */
ashleymills 0:e979170e02e7 1526 u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
ashleymills 0:e979170e02e7 1527
ashleymills 0:e979170e02e7 1528 /* Clear carry from T[i] */
ashleymills 0:e979170e02e7 1529 *tmpc++ &= MP_MASK;
ashleymills 0:e979170e02e7 1530 }
ashleymills 0:e979170e02e7 1531
ashleymills 0:e979170e02e7 1532 /* now copy higher words if any, e.g. if A has more digits than B */
ashleymills 0:e979170e02e7 1533 for (; i < max; i++) {
ashleymills 0:e979170e02e7 1534 /* T[i] = A[i] - U */
ashleymills 0:e979170e02e7 1535 *tmpc = *tmpa++ - u;
ashleymills 0:e979170e02e7 1536
ashleymills 0:e979170e02e7 1537 /* U = carry bit of T[i] */
ashleymills 0:e979170e02e7 1538 u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
ashleymills 0:e979170e02e7 1539
ashleymills 0:e979170e02e7 1540 /* Clear carry from T[i] */
ashleymills 0:e979170e02e7 1541 *tmpc++ &= MP_MASK;
ashleymills 0:e979170e02e7 1542 }
ashleymills 0:e979170e02e7 1543
ashleymills 0:e979170e02e7 1544 /* clear digits above used (since we may not have grown result above) */
ashleymills 0:e979170e02e7 1545 for (i = c->used; i < olduse; i++) {
ashleymills 0:e979170e02e7 1546 *tmpc++ = 0;
ashleymills 0:e979170e02e7 1547 }
ashleymills 0:e979170e02e7 1548 }
ashleymills 0:e979170e02e7 1549
ashleymills 0:e979170e02e7 1550 mp_clamp (c);
ashleymills 0:e979170e02e7 1551 return MP_OKAY;
ashleymills 0:e979170e02e7 1552 }
ashleymills 0:e979170e02e7 1553
ashleymills 0:e979170e02e7 1554
ashleymills 0:e979170e02e7 1555 /* high level subtraction (handles signs) */
ashleymills 0:e979170e02e7 1556 int
ashleymills 0:e979170e02e7 1557 mp_sub (mp_int * a, mp_int * b, mp_int * c)
ashleymills 0:e979170e02e7 1558 {
ashleymills 0:e979170e02e7 1559 int sa, sb, res;
ashleymills 0:e979170e02e7 1560
ashleymills 0:e979170e02e7 1561 sa = a->sign;
ashleymills 0:e979170e02e7 1562 sb = b->sign;
ashleymills 0:e979170e02e7 1563
ashleymills 0:e979170e02e7 1564 if (sa != sb) {
ashleymills 0:e979170e02e7 1565 /* subtract a negative from a positive, OR */
ashleymills 0:e979170e02e7 1566 /* subtract a positive from a negative. */
ashleymills 0:e979170e02e7 1567 /* In either case, ADD their magnitudes, */
ashleymills 0:e979170e02e7 1568 /* and use the sign of the first number. */
ashleymills 0:e979170e02e7 1569 c->sign = sa;
ashleymills 0:e979170e02e7 1570 res = s_mp_add (a, b, c);
ashleymills 0:e979170e02e7 1571 } else {
ashleymills 0:e979170e02e7 1572 /* subtract a positive from a positive, OR */
ashleymills 0:e979170e02e7 1573 /* subtract a negative from a negative. */
ashleymills 0:e979170e02e7 1574 /* First, take the difference between their */
ashleymills 0:e979170e02e7 1575 /* magnitudes, then... */
ashleymills 0:e979170e02e7 1576 if (mp_cmp_mag (a, b) != MP_LT) {
ashleymills 0:e979170e02e7 1577 /* Copy the sign from the first */
ashleymills 0:e979170e02e7 1578 c->sign = sa;
ashleymills 0:e979170e02e7 1579 /* The first has a larger or equal magnitude */
ashleymills 0:e979170e02e7 1580 res = s_mp_sub (a, b, c);
ashleymills 0:e979170e02e7 1581 } else {
ashleymills 0:e979170e02e7 1582 /* The result has the *opposite* sign from */
ashleymills 0:e979170e02e7 1583 /* the first number. */
ashleymills 0:e979170e02e7 1584 c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
ashleymills 0:e979170e02e7 1585 /* The second has a larger magnitude */
ashleymills 0:e979170e02e7 1586 res = s_mp_sub (b, a, c);
ashleymills 0:e979170e02e7 1587 }
ashleymills 0:e979170e02e7 1588 }
ashleymills 0:e979170e02e7 1589 return res;
ashleymills 0:e979170e02e7 1590 }
ashleymills 0:e979170e02e7 1591
ashleymills 0:e979170e02e7 1592
ashleymills 0:e979170e02e7 1593 /* determines if reduce_2k_l can be used */
ashleymills 0:e979170e02e7 1594 int mp_reduce_is_2k_l(mp_int *a)
ashleymills 0:e979170e02e7 1595 {
ashleymills 0:e979170e02e7 1596 int ix, iy;
ashleymills 0:e979170e02e7 1597
ashleymills 0:e979170e02e7 1598 if (a->used == 0) {
ashleymills 0:e979170e02e7 1599 return MP_NO;
ashleymills 0:e979170e02e7 1600 } else if (a->used == 1) {
ashleymills 0:e979170e02e7 1601 return MP_YES;
ashleymills 0:e979170e02e7 1602 } else if (a->used > 1) {
ashleymills 0:e979170e02e7 1603 /* if more than half of the digits are -1 we're sold */
ashleymills 0:e979170e02e7 1604 for (iy = ix = 0; ix < a->used; ix++) {
ashleymills 0:e979170e02e7 1605 if (a->dp[ix] == MP_MASK) {
ashleymills 0:e979170e02e7 1606 ++iy;
ashleymills 0:e979170e02e7 1607 }
ashleymills 0:e979170e02e7 1608 }
ashleymills 0:e979170e02e7 1609 return (iy >= (a->used/2)) ? MP_YES : MP_NO;
ashleymills 0:e979170e02e7 1610
ashleymills 0:e979170e02e7 1611 }
ashleymills 0:e979170e02e7 1612 return MP_NO;
ashleymills 0:e979170e02e7 1613 }
ashleymills 0:e979170e02e7 1614
ashleymills 0:e979170e02e7 1615
ashleymills 0:e979170e02e7 1616 /* determines if mp_reduce_2k can be used */
ashleymills 0:e979170e02e7 1617 int mp_reduce_is_2k(mp_int *a)
ashleymills 0:e979170e02e7 1618 {
ashleymills 0:e979170e02e7 1619 int ix, iy, iw;
ashleymills 0:e979170e02e7 1620 mp_digit iz;
ashleymills 0:e979170e02e7 1621
ashleymills 0:e979170e02e7 1622 if (a->used == 0) {
ashleymills 0:e979170e02e7 1623 return MP_NO;
ashleymills 0:e979170e02e7 1624 } else if (a->used == 1) {
ashleymills 0:e979170e02e7 1625 return MP_YES;
ashleymills 0:e979170e02e7 1626 } else if (a->used > 1) {
ashleymills 0:e979170e02e7 1627 iy = mp_count_bits(a);
ashleymills 0:e979170e02e7 1628 iz = 1;
ashleymills 0:e979170e02e7 1629 iw = 1;
ashleymills 0:e979170e02e7 1630
ashleymills 0:e979170e02e7 1631 /* Test every bit from the second digit up, must be 1 */
ashleymills 0:e979170e02e7 1632 for (ix = DIGIT_BIT; ix < iy; ix++) {
ashleymills 0:e979170e02e7 1633 if ((a->dp[iw] & iz) == 0) {
ashleymills 0:e979170e02e7 1634 return MP_NO;
ashleymills 0:e979170e02e7 1635 }
ashleymills 0:e979170e02e7 1636 iz <<= 1;
ashleymills 0:e979170e02e7 1637 if (iz > (mp_digit)MP_MASK) {
ashleymills 0:e979170e02e7 1638 ++iw;
ashleymills 0:e979170e02e7 1639 iz = 1;
ashleymills 0:e979170e02e7 1640 }
ashleymills 0:e979170e02e7 1641 }
ashleymills 0:e979170e02e7 1642 }
ashleymills 0:e979170e02e7 1643 return MP_YES;
ashleymills 0:e979170e02e7 1644 }
ashleymills 0:e979170e02e7 1645
ashleymills 0:e979170e02e7 1646
ashleymills 0:e979170e02e7 1647 /* determines if a number is a valid DR modulus */
ashleymills 0:e979170e02e7 1648 int mp_dr_is_modulus(mp_int *a)
ashleymills 0:e979170e02e7 1649 {
ashleymills 0:e979170e02e7 1650 int ix;
ashleymills 0:e979170e02e7 1651
ashleymills 0:e979170e02e7 1652 /* must be at least two digits */
ashleymills 0:e979170e02e7 1653 if (a->used < 2) {
ashleymills 0:e979170e02e7 1654 return 0;
ashleymills 0:e979170e02e7 1655 }
ashleymills 0:e979170e02e7 1656
ashleymills 0:e979170e02e7 1657 /* must be of the form b**k - a [a <= b] so all
ashleymills 0:e979170e02e7 1658 * but the first digit must be equal to -1 (mod b).
ashleymills 0:e979170e02e7 1659 */
ashleymills 0:e979170e02e7 1660 for (ix = 1; ix < a->used; ix++) {
ashleymills 0:e979170e02e7 1661 if (a->dp[ix] != MP_MASK) {
ashleymills 0:e979170e02e7 1662 return 0;
ashleymills 0:e979170e02e7 1663 }
ashleymills 0:e979170e02e7 1664 }
ashleymills 0:e979170e02e7 1665 return 1;
ashleymills 0:e979170e02e7 1666 }
ashleymills 0:e979170e02e7 1667
ashleymills 0:e979170e02e7 1668
ashleymills 0:e979170e02e7 1669 /* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
ashleymills 0:e979170e02e7 1670 *
ashleymills 0:e979170e02e7 1671 * Uses a left-to-right k-ary sliding window to compute the modular
ashleymills 0:e979170e02e7 1672 * exponentiation.
ashleymills 0:e979170e02e7 1673 * The value of k changes based on the size of the exponent.
ashleymills 0:e979170e02e7 1674 *
ashleymills 0:e979170e02e7 1675 * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
ashleymills 0:e979170e02e7 1676 */
ashleymills 0:e979170e02e7 1677
ashleymills 0:e979170e02e7 1678 #ifdef MP_LOW_MEM
ashleymills 0:e979170e02e7 1679 #define TAB_SIZE 32
ashleymills 0:e979170e02e7 1680 #else
ashleymills 0:e979170e02e7 1681 #define TAB_SIZE 256
ashleymills 0:e979170e02e7 1682 #endif
ashleymills 0:e979170e02e7 1683
ashleymills 0:e979170e02e7 1684 int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y,
ashleymills 0:e979170e02e7 1685 int redmode)
ashleymills 0:e979170e02e7 1686 {
ashleymills 0:e979170e02e7 1687 mp_int M[TAB_SIZE], res;
ashleymills 0:e979170e02e7 1688 mp_digit buf, mp;
ashleymills 0:e979170e02e7 1689 int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
ashleymills 0:e979170e02e7 1690
ashleymills 0:e979170e02e7 1691 /* use a pointer to the reduction algorithm. This allows us to use
ashleymills 0:e979170e02e7 1692 * one of many reduction algorithms without modding the guts of
ashleymills 0:e979170e02e7 1693 * the code with if statements everywhere.
ashleymills 0:e979170e02e7 1694 */
ashleymills 0:e979170e02e7 1695 int (*redux)(mp_int*,mp_int*,mp_digit);
ashleymills 0:e979170e02e7 1696
ashleymills 0:e979170e02e7 1697 /* find window size */
ashleymills 0:e979170e02e7 1698 x = mp_count_bits (X);
ashleymills 0:e979170e02e7 1699 if (x <= 7) {
ashleymills 0:e979170e02e7 1700 winsize = 2;
ashleymills 0:e979170e02e7 1701 } else if (x <= 36) {
ashleymills 0:e979170e02e7 1702 winsize = 3;
ashleymills 0:e979170e02e7 1703 } else if (x <= 140) {
ashleymills 0:e979170e02e7 1704 winsize = 4;
ashleymills 0:e979170e02e7 1705 } else if (x <= 450) {
ashleymills 0:e979170e02e7 1706 winsize = 5;
ashleymills 0:e979170e02e7 1707 } else if (x <= 1303) {
ashleymills 0:e979170e02e7 1708 winsize = 6;
ashleymills 0:e979170e02e7 1709 } else if (x <= 3529) {
ashleymills 0:e979170e02e7 1710 winsize = 7;
ashleymills 0:e979170e02e7 1711 } else {
ashleymills 0:e979170e02e7 1712 winsize = 8;
ashleymills 0:e979170e02e7 1713 }
ashleymills 0:e979170e02e7 1714
ashleymills 0:e979170e02e7 1715 #ifdef MP_LOW_MEM
ashleymills 0:e979170e02e7 1716 if (winsize > 5) {
ashleymills 0:e979170e02e7 1717 winsize = 5;
ashleymills 0:e979170e02e7 1718 }
ashleymills 0:e979170e02e7 1719 #endif
ashleymills 0:e979170e02e7 1720
ashleymills 0:e979170e02e7 1721 /* init M array */
ashleymills 0:e979170e02e7 1722 /* init first cell */
ashleymills 0:e979170e02e7 1723 if ((err = mp_init(&M[1])) != MP_OKAY) {
ashleymills 0:e979170e02e7 1724 return err;
ashleymills 0:e979170e02e7 1725 }
ashleymills 0:e979170e02e7 1726
ashleymills 0:e979170e02e7 1727 /* now init the second half of the array */
ashleymills 0:e979170e02e7 1728 for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
ashleymills 0:e979170e02e7 1729 if ((err = mp_init(&M[x])) != MP_OKAY) {
ashleymills 0:e979170e02e7 1730 for (y = 1<<(winsize-1); y < x; y++) {
ashleymills 0:e979170e02e7 1731 mp_clear (&M[y]);
ashleymills 0:e979170e02e7 1732 }
ashleymills 0:e979170e02e7 1733 mp_clear(&M[1]);
ashleymills 0:e979170e02e7 1734 return err;
ashleymills 0:e979170e02e7 1735 }
ashleymills 0:e979170e02e7 1736 }
ashleymills 0:e979170e02e7 1737
ashleymills 0:e979170e02e7 1738 /* determine and setup reduction code */
ashleymills 0:e979170e02e7 1739 if (redmode == 0) {
ashleymills 0:e979170e02e7 1740 #ifdef BN_MP_MONTGOMERY_SETUP_C
ashleymills 0:e979170e02e7 1741 /* now setup montgomery */
ashleymills 0:e979170e02e7 1742 if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1743 goto LBL_M;
ashleymills 0:e979170e02e7 1744 }
ashleymills 0:e979170e02e7 1745 #else
ashleymills 0:e979170e02e7 1746 err = MP_VAL;
ashleymills 0:e979170e02e7 1747 goto LBL_M;
ashleymills 0:e979170e02e7 1748 #endif
ashleymills 0:e979170e02e7 1749
ashleymills 0:e979170e02e7 1750 /* automatically pick the comba one if available (saves quite a few
ashleymills 0:e979170e02e7 1751 calls/ifs) */
ashleymills 0:e979170e02e7 1752 #ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
ashleymills 0:e979170e02e7 1753 if (((P->used * 2 + 1) < MP_WARRAY) &&
ashleymills 0:e979170e02e7 1754 P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
ashleymills 0:e979170e02e7 1755 redux = fast_mp_montgomery_reduce;
ashleymills 0:e979170e02e7 1756 } else
ashleymills 0:e979170e02e7 1757 #endif
ashleymills 0:e979170e02e7 1758 {
ashleymills 0:e979170e02e7 1759 #ifdef BN_MP_MONTGOMERY_REDUCE_C
ashleymills 0:e979170e02e7 1760 /* use slower baseline Montgomery method */
ashleymills 0:e979170e02e7 1761 redux = mp_montgomery_reduce;
ashleymills 0:e979170e02e7 1762 #else
ashleymills 0:e979170e02e7 1763 err = MP_VAL;
ashleymills 0:e979170e02e7 1764 goto LBL_M;
ashleymills 0:e979170e02e7 1765 #endif
ashleymills 0:e979170e02e7 1766 }
ashleymills 0:e979170e02e7 1767 } else if (redmode == 1) {
ashleymills 0:e979170e02e7 1768 #if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
ashleymills 0:e979170e02e7 1769 /* setup DR reduction for moduli of the form B**k - b */
ashleymills 0:e979170e02e7 1770 mp_dr_setup(P, &mp);
ashleymills 0:e979170e02e7 1771 redux = mp_dr_reduce;
ashleymills 0:e979170e02e7 1772 #else
ashleymills 0:e979170e02e7 1773 err = MP_VAL;
ashleymills 0:e979170e02e7 1774 goto LBL_M;
ashleymills 0:e979170e02e7 1775 #endif
ashleymills 0:e979170e02e7 1776 } else {
ashleymills 0:e979170e02e7 1777 #if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
ashleymills 0:e979170e02e7 1778 /* setup DR reduction for moduli of the form 2**k - b */
ashleymills 0:e979170e02e7 1779 if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1780 goto LBL_M;
ashleymills 0:e979170e02e7 1781 }
ashleymills 0:e979170e02e7 1782 redux = mp_reduce_2k;
ashleymills 0:e979170e02e7 1783 #else
ashleymills 0:e979170e02e7 1784 err = MP_VAL;
ashleymills 0:e979170e02e7 1785 goto LBL_M;
ashleymills 0:e979170e02e7 1786 #endif
ashleymills 0:e979170e02e7 1787 }
ashleymills 0:e979170e02e7 1788
ashleymills 0:e979170e02e7 1789 /* setup result */
ashleymills 0:e979170e02e7 1790 if ((err = mp_init (&res)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1791 goto LBL_M;
ashleymills 0:e979170e02e7 1792 }
ashleymills 0:e979170e02e7 1793
ashleymills 0:e979170e02e7 1794 /* create M table
ashleymills 0:e979170e02e7 1795 *
ashleymills 0:e979170e02e7 1796
ashleymills 0:e979170e02e7 1797 *
ashleymills 0:e979170e02e7 1798 * The first half of the table is not computed though accept for M[0] and M[1]
ashleymills 0:e979170e02e7 1799 */
ashleymills 0:e979170e02e7 1800
ashleymills 0:e979170e02e7 1801 if (redmode == 0) {
ashleymills 0:e979170e02e7 1802 #ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
ashleymills 0:e979170e02e7 1803 /* now we need R mod m */
ashleymills 0:e979170e02e7 1804 if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1805 goto LBL_RES;
ashleymills 0:e979170e02e7 1806 }
ashleymills 0:e979170e02e7 1807 #else
ashleymills 0:e979170e02e7 1808 err = MP_VAL;
ashleymills 0:e979170e02e7 1809 goto LBL_RES;
ashleymills 0:e979170e02e7 1810 #endif
ashleymills 0:e979170e02e7 1811
ashleymills 0:e979170e02e7 1812 /* now set M[1] to G * R mod m */
ashleymills 0:e979170e02e7 1813 if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
ashleymills 0:e979170e02e7 1814 goto LBL_RES;
ashleymills 0:e979170e02e7 1815 }
ashleymills 0:e979170e02e7 1816 } else {
ashleymills 0:e979170e02e7 1817 mp_set(&res, 1);
ashleymills 0:e979170e02e7 1818 if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
ashleymills 0:e979170e02e7 1819 goto LBL_RES;
ashleymills 0:e979170e02e7 1820 }
ashleymills 0:e979170e02e7 1821 }
ashleymills 0:e979170e02e7 1822
ashleymills 0:e979170e02e7 1823 /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times*/
ashleymills 0:e979170e02e7 1824 if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
ashleymills 0:e979170e02e7 1825 goto LBL_RES;
ashleymills 0:e979170e02e7 1826 }
ashleymills 0:e979170e02e7 1827
ashleymills 0:e979170e02e7 1828 for (x = 0; x < (winsize - 1); x++) {
ashleymills 0:e979170e02e7 1829 if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) {
ashleymills 0:e979170e02e7 1830 goto LBL_RES;
ashleymills 0:e979170e02e7 1831 }
ashleymills 0:e979170e02e7 1832 if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1833 goto LBL_RES;
ashleymills 0:e979170e02e7 1834 }
ashleymills 0:e979170e02e7 1835 }
ashleymills 0:e979170e02e7 1836
ashleymills 0:e979170e02e7 1837 /* create upper table */
ashleymills 0:e979170e02e7 1838 for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
ashleymills 0:e979170e02e7 1839 if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
ashleymills 0:e979170e02e7 1840 goto LBL_RES;
ashleymills 0:e979170e02e7 1841 }
ashleymills 0:e979170e02e7 1842 if ((err = redux (&M[x], P, mp)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1843 goto LBL_RES;
ashleymills 0:e979170e02e7 1844 }
ashleymills 0:e979170e02e7 1845 }
ashleymills 0:e979170e02e7 1846
ashleymills 0:e979170e02e7 1847 /* set initial mode and bit cnt */
ashleymills 0:e979170e02e7 1848 mode = 0;
ashleymills 0:e979170e02e7 1849 bitcnt = 1;
ashleymills 0:e979170e02e7 1850 buf = 0;
ashleymills 0:e979170e02e7 1851 digidx = X->used - 1;
ashleymills 0:e979170e02e7 1852 bitcpy = 0;
ashleymills 0:e979170e02e7 1853 bitbuf = 0;
ashleymills 0:e979170e02e7 1854
ashleymills 0:e979170e02e7 1855 for (;;) {
ashleymills 0:e979170e02e7 1856 /* grab next digit as required */
ashleymills 0:e979170e02e7 1857 if (--bitcnt == 0) {
ashleymills 0:e979170e02e7 1858 /* if digidx == -1 we are out of digits so break */
ashleymills 0:e979170e02e7 1859 if (digidx == -1) {
ashleymills 0:e979170e02e7 1860 break;
ashleymills 0:e979170e02e7 1861 }
ashleymills 0:e979170e02e7 1862 /* read next digit and reset bitcnt */
ashleymills 0:e979170e02e7 1863 buf = X->dp[digidx--];
ashleymills 0:e979170e02e7 1864 bitcnt = (int)DIGIT_BIT;
ashleymills 0:e979170e02e7 1865 }
ashleymills 0:e979170e02e7 1866
ashleymills 0:e979170e02e7 1867 /* grab the next msb from the exponent */
ashleymills 0:e979170e02e7 1868 y = (int)(buf >> (DIGIT_BIT - 1)) & 1;
ashleymills 0:e979170e02e7 1869 buf <<= (mp_digit)1;
ashleymills 0:e979170e02e7 1870
ashleymills 0:e979170e02e7 1871 /* if the bit is zero and mode == 0 then we ignore it
ashleymills 0:e979170e02e7 1872 * These represent the leading zero bits before the first 1 bit
ashleymills 0:e979170e02e7 1873 * in the exponent. Technically this opt is not required but it
ashleymills 0:e979170e02e7 1874 * does lower the # of trivial squaring/reductions used
ashleymills 0:e979170e02e7 1875 */
ashleymills 0:e979170e02e7 1876 if (mode == 0 && y == 0) {
ashleymills 0:e979170e02e7 1877 continue;
ashleymills 0:e979170e02e7 1878 }
ashleymills 0:e979170e02e7 1879
ashleymills 0:e979170e02e7 1880 /* if the bit is zero and mode == 1 then we square */
ashleymills 0:e979170e02e7 1881 if (mode == 1 && y == 0) {
ashleymills 0:e979170e02e7 1882 if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1883 goto LBL_RES;
ashleymills 0:e979170e02e7 1884 }
ashleymills 0:e979170e02e7 1885 if ((err = redux (&res, P, mp)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1886 goto LBL_RES;
ashleymills 0:e979170e02e7 1887 }
ashleymills 0:e979170e02e7 1888 continue;
ashleymills 0:e979170e02e7 1889 }
ashleymills 0:e979170e02e7 1890
ashleymills 0:e979170e02e7 1891 /* else we add it to the window */
ashleymills 0:e979170e02e7 1892 bitbuf |= (y << (winsize - ++bitcpy));
ashleymills 0:e979170e02e7 1893 mode = 2;
ashleymills 0:e979170e02e7 1894
ashleymills 0:e979170e02e7 1895 if (bitcpy == winsize) {
ashleymills 0:e979170e02e7 1896 /* ok window is filled so square as required and multiply */
ashleymills 0:e979170e02e7 1897 /* square first */
ashleymills 0:e979170e02e7 1898 for (x = 0; x < winsize; x++) {
ashleymills 0:e979170e02e7 1899 if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1900 goto LBL_RES;
ashleymills 0:e979170e02e7 1901 }
ashleymills 0:e979170e02e7 1902 if ((err = redux (&res, P, mp)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1903 goto LBL_RES;
ashleymills 0:e979170e02e7 1904 }
ashleymills 0:e979170e02e7 1905 }
ashleymills 0:e979170e02e7 1906
ashleymills 0:e979170e02e7 1907 /* then multiply */
ashleymills 0:e979170e02e7 1908 if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1909 goto LBL_RES;
ashleymills 0:e979170e02e7 1910 }
ashleymills 0:e979170e02e7 1911 if ((err = redux (&res, P, mp)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1912 goto LBL_RES;
ashleymills 0:e979170e02e7 1913 }
ashleymills 0:e979170e02e7 1914
ashleymills 0:e979170e02e7 1915 /* empty window and reset */
ashleymills 0:e979170e02e7 1916 bitcpy = 0;
ashleymills 0:e979170e02e7 1917 bitbuf = 0;
ashleymills 0:e979170e02e7 1918 mode = 1;
ashleymills 0:e979170e02e7 1919 }
ashleymills 0:e979170e02e7 1920 }
ashleymills 0:e979170e02e7 1921
ashleymills 0:e979170e02e7 1922 /* if bits remain then square/multiply */
ashleymills 0:e979170e02e7 1923 if (mode == 2 && bitcpy > 0) {
ashleymills 0:e979170e02e7 1924 /* square then multiply if the bit is set */
ashleymills 0:e979170e02e7 1925 for (x = 0; x < bitcpy; x++) {
ashleymills 0:e979170e02e7 1926 if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1927 goto LBL_RES;
ashleymills 0:e979170e02e7 1928 }
ashleymills 0:e979170e02e7 1929 if ((err = redux (&res, P, mp)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1930 goto LBL_RES;
ashleymills 0:e979170e02e7 1931 }
ashleymills 0:e979170e02e7 1932
ashleymills 0:e979170e02e7 1933 /* get next bit of the window */
ashleymills 0:e979170e02e7 1934 bitbuf <<= 1;
ashleymills 0:e979170e02e7 1935 if ((bitbuf & (1 << winsize)) != 0) {
ashleymills 0:e979170e02e7 1936 /* then multiply */
ashleymills 0:e979170e02e7 1937 if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1938 goto LBL_RES;
ashleymills 0:e979170e02e7 1939 }
ashleymills 0:e979170e02e7 1940 if ((err = redux (&res, P, mp)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1941 goto LBL_RES;
ashleymills 0:e979170e02e7 1942 }
ashleymills 0:e979170e02e7 1943 }
ashleymills 0:e979170e02e7 1944 }
ashleymills 0:e979170e02e7 1945 }
ashleymills 0:e979170e02e7 1946
ashleymills 0:e979170e02e7 1947 if (redmode == 0) {
ashleymills 0:e979170e02e7 1948 /* fixup result if Montgomery reduction is used
ashleymills 0:e979170e02e7 1949 * recall that any value in a Montgomery system is
ashleymills 0:e979170e02e7 1950 * actually multiplied by R mod n. So we have
ashleymills 0:e979170e02e7 1951 * to reduce one more time to cancel out the factor
ashleymills 0:e979170e02e7 1952 * of R.
ashleymills 0:e979170e02e7 1953 */
ashleymills 0:e979170e02e7 1954 if ((err = redux(&res, P, mp)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1955 goto LBL_RES;
ashleymills 0:e979170e02e7 1956 }
ashleymills 0:e979170e02e7 1957 }
ashleymills 0:e979170e02e7 1958
ashleymills 0:e979170e02e7 1959 /* swap res with Y */
ashleymills 0:e979170e02e7 1960 mp_exch (&res, Y);
ashleymills 0:e979170e02e7 1961 err = MP_OKAY;
ashleymills 0:e979170e02e7 1962 LBL_RES:mp_clear (&res);
ashleymills 0:e979170e02e7 1963 LBL_M:
ashleymills 0:e979170e02e7 1964 mp_clear(&M[1]);
ashleymills 0:e979170e02e7 1965 for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
ashleymills 0:e979170e02e7 1966 mp_clear (&M[x]);
ashleymills 0:e979170e02e7 1967 }
ashleymills 0:e979170e02e7 1968 return err;
ashleymills 0:e979170e02e7 1969 }
ashleymills 0:e979170e02e7 1970
ashleymills 0:e979170e02e7 1971
ashleymills 0:e979170e02e7 1972 /* setups the montgomery reduction stuff */
ashleymills 0:e979170e02e7 1973 int
ashleymills 0:e979170e02e7 1974 mp_montgomery_setup (mp_int * n, mp_digit * rho)
ashleymills 0:e979170e02e7 1975 {
ashleymills 0:e979170e02e7 1976 mp_digit x, b;
ashleymills 0:e979170e02e7 1977
ashleymills 0:e979170e02e7 1978 /* fast inversion mod 2**k
ashleymills 0:e979170e02e7 1979 *
ashleymills 0:e979170e02e7 1980 * Based on the fact that
ashleymills 0:e979170e02e7 1981 *
ashleymills 0:e979170e02e7 1982 * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n)
ashleymills 0:e979170e02e7 1983 * => 2*X*A - X*X*A*A = 1
ashleymills 0:e979170e02e7 1984 * => 2*(1) - (1) = 1
ashleymills 0:e979170e02e7 1985 */
ashleymills 0:e979170e02e7 1986 b = n->dp[0];
ashleymills 0:e979170e02e7 1987
ashleymills 0:e979170e02e7 1988 if ((b & 1) == 0) {
ashleymills 0:e979170e02e7 1989 return MP_VAL;
ashleymills 0:e979170e02e7 1990 }
ashleymills 0:e979170e02e7 1991
ashleymills 0:e979170e02e7 1992 x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
ashleymills 0:e979170e02e7 1993 x *= 2 - b * x; /* here x*a==1 mod 2**8 */
ashleymills 0:e979170e02e7 1994 #if !defined(MP_8BIT)
ashleymills 0:e979170e02e7 1995 x *= 2 - b * x; /* here x*a==1 mod 2**16 */
ashleymills 0:e979170e02e7 1996 #endif
ashleymills 0:e979170e02e7 1997 #if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
ashleymills 0:e979170e02e7 1998 x *= 2 - b * x; /* here x*a==1 mod 2**32 */
ashleymills 0:e979170e02e7 1999 #endif
ashleymills 0:e979170e02e7 2000 #ifdef MP_64BIT
ashleymills 0:e979170e02e7 2001 x *= 2 - b * x; /* here x*a==1 mod 2**64 */
ashleymills 0:e979170e02e7 2002 #endif
ashleymills 0:e979170e02e7 2003
ashleymills 0:e979170e02e7 2004 /* rho = -1/m mod b */
ashleymills 0:e979170e02e7 2005 /* TAO, switched mp_word casts to mp_digit to shut up compiler */
ashleymills 0:e979170e02e7 2006 *rho = (((mp_digit)1 << ((mp_digit) DIGIT_BIT)) - x) & MP_MASK;
ashleymills 0:e979170e02e7 2007
ashleymills 0:e979170e02e7 2008 return MP_OKAY;
ashleymills 0:e979170e02e7 2009 }
ashleymills 0:e979170e02e7 2010
ashleymills 0:e979170e02e7 2011
ashleymills 0:e979170e02e7 2012 /* computes xR**-1 == x (mod N) via Montgomery Reduction
ashleymills 0:e979170e02e7 2013 *
ashleymills 0:e979170e02e7 2014 * This is an optimized implementation of montgomery_reduce
ashleymills 0:e979170e02e7 2015 * which uses the comba method to quickly calculate the columns of the
ashleymills 0:e979170e02e7 2016 * reduction.
ashleymills 0:e979170e02e7 2017 *
ashleymills 0:e979170e02e7 2018 * Based on Algorithm 14.32 on pp.601 of HAC.
ashleymills 0:e979170e02e7 2019 */
ashleymills 0:e979170e02e7 2020 int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
ashleymills 0:e979170e02e7 2021 {
ashleymills 0:e979170e02e7 2022 int ix, res, olduse;
ashleymills 0:e979170e02e7 2023 #ifdef CYASSL_SMALL_STACK
ashleymills 0:e979170e02e7 2024 mp_word* W; /* uses dynamic memory and slower */
ashleymills 0:e979170e02e7 2025 #else
ashleymills 0:e979170e02e7 2026 mp_word W[MP_WARRAY];
ashleymills 0:e979170e02e7 2027 #endif
ashleymills 0:e979170e02e7 2028
ashleymills 0:e979170e02e7 2029 /* get old used count */
ashleymills 0:e979170e02e7 2030 olduse = x->used;
ashleymills 0:e979170e02e7 2031
ashleymills 0:e979170e02e7 2032 /* grow a as required */
ashleymills 0:e979170e02e7 2033 if (x->alloc < n->used + 1) {
ashleymills 0:e979170e02e7 2034 if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2035 return res;
ashleymills 0:e979170e02e7 2036 }
ashleymills 0:e979170e02e7 2037 }
ashleymills 0:e979170e02e7 2038
ashleymills 0:e979170e02e7 2039 #ifdef CYASSL_SMALL_STACK
ashleymills 0:e979170e02e7 2040 W = (mp_word*)XMALLOC(sizeof(mp_word) * MP_WARRAY, 0, DYNAMIC_TYPE_BIGINT);
ashleymills 0:e979170e02e7 2041 if (W == NULL)
ashleymills 0:e979170e02e7 2042 return MP_MEM;
ashleymills 0:e979170e02e7 2043 #endif
ashleymills 0:e979170e02e7 2044
ashleymills 0:e979170e02e7 2045 /* first we have to get the digits of the input into
ashleymills 0:e979170e02e7 2046 * an array of double precision words W[...]
ashleymills 0:e979170e02e7 2047 */
ashleymills 0:e979170e02e7 2048 {
ashleymills 0:e979170e02e7 2049 register mp_word *_W;
ashleymills 0:e979170e02e7 2050 register mp_digit *tmpx;
ashleymills 0:e979170e02e7 2051
ashleymills 0:e979170e02e7 2052 /* alias for the W[] array */
ashleymills 0:e979170e02e7 2053 _W = W;
ashleymills 0:e979170e02e7 2054
ashleymills 0:e979170e02e7 2055 /* alias for the digits of x*/
ashleymills 0:e979170e02e7 2056 tmpx = x->dp;
ashleymills 0:e979170e02e7 2057
ashleymills 0:e979170e02e7 2058 /* copy the digits of a into W[0..a->used-1] */
ashleymills 0:e979170e02e7 2059 for (ix = 0; ix < x->used; ix++) {
ashleymills 0:e979170e02e7 2060 *_W++ = *tmpx++;
ashleymills 0:e979170e02e7 2061 }
ashleymills 0:e979170e02e7 2062
ashleymills 0:e979170e02e7 2063 /* zero the high words of W[a->used..m->used*2] */
ashleymills 0:e979170e02e7 2064 for (; ix < n->used * 2 + 1; ix++) {
ashleymills 0:e979170e02e7 2065 *_W++ = 0;
ashleymills 0:e979170e02e7 2066 }
ashleymills 0:e979170e02e7 2067 }
ashleymills 0:e979170e02e7 2068
ashleymills 0:e979170e02e7 2069 /* now we proceed to zero successive digits
ashleymills 0:e979170e02e7 2070 * from the least significant upwards
ashleymills 0:e979170e02e7 2071 */
ashleymills 0:e979170e02e7 2072 for (ix = 0; ix < n->used; ix++) {
ashleymills 0:e979170e02e7 2073 /* mu = ai * m' mod b
ashleymills 0:e979170e02e7 2074 *
ashleymills 0:e979170e02e7 2075 * We avoid a double precision multiplication (which isn't required)
ashleymills 0:e979170e02e7 2076 * by casting the value down to a mp_digit. Note this requires
ashleymills 0:e979170e02e7 2077 * that W[ix-1] have the carry cleared (see after the inner loop)
ashleymills 0:e979170e02e7 2078 */
ashleymills 0:e979170e02e7 2079 register mp_digit mu;
ashleymills 0:e979170e02e7 2080 mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
ashleymills 0:e979170e02e7 2081
ashleymills 0:e979170e02e7 2082 /* a = a + mu * m * b**i
ashleymills 0:e979170e02e7 2083 *
ashleymills 0:e979170e02e7 2084 * This is computed in place and on the fly. The multiplication
ashleymills 0:e979170e02e7 2085 * by b**i is handled by offseting which columns the results
ashleymills 0:e979170e02e7 2086 * are added to.
ashleymills 0:e979170e02e7 2087 *
ashleymills 0:e979170e02e7 2088 * Note the comba method normally doesn't handle carries in the
ashleymills 0:e979170e02e7 2089 * inner loop In this case we fix the carry from the previous
ashleymills 0:e979170e02e7 2090 * column since the Montgomery reduction requires digits of the
ashleymills 0:e979170e02e7 2091 * result (so far) [see above] to work. This is
ashleymills 0:e979170e02e7 2092 * handled by fixing up one carry after the inner loop. The
ashleymills 0:e979170e02e7 2093 * carry fixups are done in order so after these loops the
ashleymills 0:e979170e02e7 2094 * first m->used words of W[] have the carries fixed
ashleymills 0:e979170e02e7 2095 */
ashleymills 0:e979170e02e7 2096 {
ashleymills 0:e979170e02e7 2097 register int iy;
ashleymills 0:e979170e02e7 2098 register mp_digit *tmpn;
ashleymills 0:e979170e02e7 2099 register mp_word *_W;
ashleymills 0:e979170e02e7 2100
ashleymills 0:e979170e02e7 2101 /* alias for the digits of the modulus */
ashleymills 0:e979170e02e7 2102 tmpn = n->dp;
ashleymills 0:e979170e02e7 2103
ashleymills 0:e979170e02e7 2104 /* Alias for the columns set by an offset of ix */
ashleymills 0:e979170e02e7 2105 _W = W + ix;
ashleymills 0:e979170e02e7 2106
ashleymills 0:e979170e02e7 2107 /* inner loop */
ashleymills 0:e979170e02e7 2108 for (iy = 0; iy < n->used; iy++) {
ashleymills 0:e979170e02e7 2109 *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
ashleymills 0:e979170e02e7 2110 }
ashleymills 0:e979170e02e7 2111 }
ashleymills 0:e979170e02e7 2112
ashleymills 0:e979170e02e7 2113 /* now fix carry for next digit, W[ix+1] */
ashleymills 0:e979170e02e7 2114 W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
ashleymills 0:e979170e02e7 2115 }
ashleymills 0:e979170e02e7 2116
ashleymills 0:e979170e02e7 2117 /* now we have to propagate the carries and
ashleymills 0:e979170e02e7 2118 * shift the words downward [all those least
ashleymills 0:e979170e02e7 2119 * significant digits we zeroed].
ashleymills 0:e979170e02e7 2120 */
ashleymills 0:e979170e02e7 2121 {
ashleymills 0:e979170e02e7 2122 register mp_digit *tmpx;
ashleymills 0:e979170e02e7 2123 register mp_word *_W, *_W1;
ashleymills 0:e979170e02e7 2124
ashleymills 0:e979170e02e7 2125 /* nox fix rest of carries */
ashleymills 0:e979170e02e7 2126
ashleymills 0:e979170e02e7 2127 /* alias for current word */
ashleymills 0:e979170e02e7 2128 _W1 = W + ix;
ashleymills 0:e979170e02e7 2129
ashleymills 0:e979170e02e7 2130 /* alias for next word, where the carry goes */
ashleymills 0:e979170e02e7 2131 _W = W + ++ix;
ashleymills 0:e979170e02e7 2132
ashleymills 0:e979170e02e7 2133 for (; ix <= n->used * 2 + 1; ix++) {
ashleymills 0:e979170e02e7 2134 *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
ashleymills 0:e979170e02e7 2135 }
ashleymills 0:e979170e02e7 2136
ashleymills 0:e979170e02e7 2137 /* copy out, A = A/b**n
ashleymills 0:e979170e02e7 2138 *
ashleymills 0:e979170e02e7 2139 * The result is A/b**n but instead of converting from an
ashleymills 0:e979170e02e7 2140 * array of mp_word to mp_digit than calling mp_rshd
ashleymills 0:e979170e02e7 2141 * we just copy them in the right order
ashleymills 0:e979170e02e7 2142 */
ashleymills 0:e979170e02e7 2143
ashleymills 0:e979170e02e7 2144 /* alias for destination word */
ashleymills 0:e979170e02e7 2145 tmpx = x->dp;
ashleymills 0:e979170e02e7 2146
ashleymills 0:e979170e02e7 2147 /* alias for shifted double precision result */
ashleymills 0:e979170e02e7 2148 _W = W + n->used;
ashleymills 0:e979170e02e7 2149
ashleymills 0:e979170e02e7 2150 for (ix = 0; ix < n->used + 1; ix++) {
ashleymills 0:e979170e02e7 2151 *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
ashleymills 0:e979170e02e7 2152 }
ashleymills 0:e979170e02e7 2153
ashleymills 0:e979170e02e7 2154 /* zero oldused digits, if the input a was larger than
ashleymills 0:e979170e02e7 2155 * m->used+1 we'll have to clear the digits
ashleymills 0:e979170e02e7 2156 */
ashleymills 0:e979170e02e7 2157 for (; ix < olduse; ix++) {
ashleymills 0:e979170e02e7 2158 *tmpx++ = 0;
ashleymills 0:e979170e02e7 2159 }
ashleymills 0:e979170e02e7 2160 }
ashleymills 0:e979170e02e7 2161
ashleymills 0:e979170e02e7 2162 /* set the max used and clamp */
ashleymills 0:e979170e02e7 2163 x->used = n->used + 1;
ashleymills 0:e979170e02e7 2164 mp_clamp (x);
ashleymills 0:e979170e02e7 2165
ashleymills 0:e979170e02e7 2166 #ifdef CYASSL_SMALL_STACK
ashleymills 0:e979170e02e7 2167 XFREE(W, 0, DYNAMIC_TYPE_BIGINT);
ashleymills 0:e979170e02e7 2168 #endif
ashleymills 0:e979170e02e7 2169
ashleymills 0:e979170e02e7 2170 /* if A >= m then A = A - m */
ashleymills 0:e979170e02e7 2171 if (mp_cmp_mag (x, n) != MP_LT) {
ashleymills 0:e979170e02e7 2172 return s_mp_sub (x, n, x);
ashleymills 0:e979170e02e7 2173 }
ashleymills 0:e979170e02e7 2174 return MP_OKAY;
ashleymills 0:e979170e02e7 2175 }
ashleymills 0:e979170e02e7 2176
ashleymills 0:e979170e02e7 2177
ashleymills 0:e979170e02e7 2178 /* computes xR**-1 == x (mod N) via Montgomery Reduction */
ashleymills 0:e979170e02e7 2179 int
ashleymills 0:e979170e02e7 2180 mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
ashleymills 0:e979170e02e7 2181 {
ashleymills 0:e979170e02e7 2182 int ix, res, digs;
ashleymills 0:e979170e02e7 2183 mp_digit mu;
ashleymills 0:e979170e02e7 2184
ashleymills 0:e979170e02e7 2185 /* can the fast reduction [comba] method be used?
ashleymills 0:e979170e02e7 2186 *
ashleymills 0:e979170e02e7 2187 * Note that unlike in mul you're safely allowed *less*
ashleymills 0:e979170e02e7 2188 * than the available columns [255 per default] since carries
ashleymills 0:e979170e02e7 2189 * are fixed up in the inner loop.
ashleymills 0:e979170e02e7 2190 */
ashleymills 0:e979170e02e7 2191 digs = n->used * 2 + 1;
ashleymills 0:e979170e02e7 2192 if ((digs < MP_WARRAY) &&
ashleymills 0:e979170e02e7 2193 n->used <
ashleymills 0:e979170e02e7 2194 (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
ashleymills 0:e979170e02e7 2195 return fast_mp_montgomery_reduce (x, n, rho);
ashleymills 0:e979170e02e7 2196 }
ashleymills 0:e979170e02e7 2197
ashleymills 0:e979170e02e7 2198 /* grow the input as required */
ashleymills 0:e979170e02e7 2199 if (x->alloc < digs) {
ashleymills 0:e979170e02e7 2200 if ((res = mp_grow (x, digs)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2201 return res;
ashleymills 0:e979170e02e7 2202 }
ashleymills 0:e979170e02e7 2203 }
ashleymills 0:e979170e02e7 2204 x->used = digs;
ashleymills 0:e979170e02e7 2205
ashleymills 0:e979170e02e7 2206 for (ix = 0; ix < n->used; ix++) {
ashleymills 0:e979170e02e7 2207 /* mu = ai * rho mod b
ashleymills 0:e979170e02e7 2208 *
ashleymills 0:e979170e02e7 2209 * The value of rho must be precalculated via
ashleymills 0:e979170e02e7 2210 * montgomery_setup() such that
ashleymills 0:e979170e02e7 2211 * it equals -1/n0 mod b this allows the
ashleymills 0:e979170e02e7 2212 * following inner loop to reduce the
ashleymills 0:e979170e02e7 2213 * input one digit at a time
ashleymills 0:e979170e02e7 2214 */
ashleymills 0:e979170e02e7 2215 mu = (mp_digit) (((mp_word)x->dp[ix]) * ((mp_word)rho) & MP_MASK);
ashleymills 0:e979170e02e7 2216
ashleymills 0:e979170e02e7 2217 /* a = a + mu * m * b**i */
ashleymills 0:e979170e02e7 2218 {
ashleymills 0:e979170e02e7 2219 register int iy;
ashleymills 0:e979170e02e7 2220 register mp_digit *tmpn, *tmpx, u;
ashleymills 0:e979170e02e7 2221 register mp_word r;
ashleymills 0:e979170e02e7 2222
ashleymills 0:e979170e02e7 2223 /* alias for digits of the modulus */
ashleymills 0:e979170e02e7 2224 tmpn = n->dp;
ashleymills 0:e979170e02e7 2225
ashleymills 0:e979170e02e7 2226 /* alias for the digits of x [the input] */
ashleymills 0:e979170e02e7 2227 tmpx = x->dp + ix;
ashleymills 0:e979170e02e7 2228
ashleymills 0:e979170e02e7 2229 /* set the carry to zero */
ashleymills 0:e979170e02e7 2230 u = 0;
ashleymills 0:e979170e02e7 2231
ashleymills 0:e979170e02e7 2232 /* Multiply and add in place */
ashleymills 0:e979170e02e7 2233 for (iy = 0; iy < n->used; iy++) {
ashleymills 0:e979170e02e7 2234 /* compute product and sum */
ashleymills 0:e979170e02e7 2235 r = ((mp_word)mu) * ((mp_word)*tmpn++) +
ashleymills 0:e979170e02e7 2236 ((mp_word) u) + ((mp_word) * tmpx);
ashleymills 0:e979170e02e7 2237
ashleymills 0:e979170e02e7 2238 /* get carry */
ashleymills 0:e979170e02e7 2239 u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
ashleymills 0:e979170e02e7 2240
ashleymills 0:e979170e02e7 2241 /* fix digit */
ashleymills 0:e979170e02e7 2242 *tmpx++ = (mp_digit)(r & ((mp_word) MP_MASK));
ashleymills 0:e979170e02e7 2243 }
ashleymills 0:e979170e02e7 2244 /* At this point the ix'th digit of x should be zero */
ashleymills 0:e979170e02e7 2245
ashleymills 0:e979170e02e7 2246
ashleymills 0:e979170e02e7 2247 /* propagate carries upwards as required*/
ashleymills 0:e979170e02e7 2248 while (u) {
ashleymills 0:e979170e02e7 2249 *tmpx += u;
ashleymills 0:e979170e02e7 2250 u = *tmpx >> DIGIT_BIT;
ashleymills 0:e979170e02e7 2251 *tmpx++ &= MP_MASK;
ashleymills 0:e979170e02e7 2252 }
ashleymills 0:e979170e02e7 2253 }
ashleymills 0:e979170e02e7 2254 }
ashleymills 0:e979170e02e7 2255
ashleymills 0:e979170e02e7 2256 /* at this point the n.used'th least
ashleymills 0:e979170e02e7 2257 * significant digits of x are all zero
ashleymills 0:e979170e02e7 2258 * which means we can shift x to the
ashleymills 0:e979170e02e7 2259 * right by n.used digits and the
ashleymills 0:e979170e02e7 2260 * residue is unchanged.
ashleymills 0:e979170e02e7 2261 */
ashleymills 0:e979170e02e7 2262
ashleymills 0:e979170e02e7 2263 /* x = x/b**n.used */
ashleymills 0:e979170e02e7 2264 mp_clamp(x);
ashleymills 0:e979170e02e7 2265 mp_rshd (x, n->used);
ashleymills 0:e979170e02e7 2266
ashleymills 0:e979170e02e7 2267 /* if x >= n then x = x - n */
ashleymills 0:e979170e02e7 2268 if (mp_cmp_mag (x, n) != MP_LT) {
ashleymills 0:e979170e02e7 2269 return s_mp_sub (x, n, x);
ashleymills 0:e979170e02e7 2270 }
ashleymills 0:e979170e02e7 2271
ashleymills 0:e979170e02e7 2272 return MP_OKAY;
ashleymills 0:e979170e02e7 2273 }
ashleymills 0:e979170e02e7 2274
ashleymills 0:e979170e02e7 2275
ashleymills 0:e979170e02e7 2276 /* determines the setup value */
ashleymills 0:e979170e02e7 2277 void mp_dr_setup(mp_int *a, mp_digit *d)
ashleymills 0:e979170e02e7 2278 {
ashleymills 0:e979170e02e7 2279 /* the casts are required if DIGIT_BIT is one less than
ashleymills 0:e979170e02e7 2280 * the number of bits in a mp_digit [e.g. DIGIT_BIT==31]
ashleymills 0:e979170e02e7 2281 */
ashleymills 0:e979170e02e7 2282 *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) -
ashleymills 0:e979170e02e7 2283 ((mp_word)a->dp[0]));
ashleymills 0:e979170e02e7 2284 }
ashleymills 0:e979170e02e7 2285
ashleymills 0:e979170e02e7 2286
ashleymills 0:e979170e02e7 2287 /* reduce "x" in place modulo "n" using the Diminished Radix algorithm.
ashleymills 0:e979170e02e7 2288 *
ashleymills 0:e979170e02e7 2289 * Based on algorithm from the paper
ashleymills 0:e979170e02e7 2290 *
ashleymills 0:e979170e02e7 2291 * "Generating Efficient Primes for Discrete Log Cryptosystems"
ashleymills 0:e979170e02e7 2292 * Chae Hoon Lim, Pil Joong Lee,
ashleymills 0:e979170e02e7 2293 * POSTECH Information Research Laboratories
ashleymills 0:e979170e02e7 2294 *
ashleymills 0:e979170e02e7 2295 * The modulus must be of a special format [see manual]
ashleymills 0:e979170e02e7 2296 *
ashleymills 0:e979170e02e7 2297 * Has been modified to use algorithm 7.10 from the LTM book instead
ashleymills 0:e979170e02e7 2298 *
ashleymills 0:e979170e02e7 2299 * Input x must be in the range 0 <= x <= (n-1)**2
ashleymills 0:e979170e02e7 2300 */
ashleymills 0:e979170e02e7 2301 int
ashleymills 0:e979170e02e7 2302 mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k)
ashleymills 0:e979170e02e7 2303 {
ashleymills 0:e979170e02e7 2304 int err, i, m;
ashleymills 0:e979170e02e7 2305 mp_word r;
ashleymills 0:e979170e02e7 2306 mp_digit mu, *tmpx1, *tmpx2;
ashleymills 0:e979170e02e7 2307
ashleymills 0:e979170e02e7 2308 /* m = digits in modulus */
ashleymills 0:e979170e02e7 2309 m = n->used;
ashleymills 0:e979170e02e7 2310
ashleymills 0:e979170e02e7 2311 /* ensure that "x" has at least 2m digits */
ashleymills 0:e979170e02e7 2312 if (x->alloc < m + m) {
ashleymills 0:e979170e02e7 2313 if ((err = mp_grow (x, m + m)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2314 return err;
ashleymills 0:e979170e02e7 2315 }
ashleymills 0:e979170e02e7 2316 }
ashleymills 0:e979170e02e7 2317
ashleymills 0:e979170e02e7 2318 /* top of loop, this is where the code resumes if
ashleymills 0:e979170e02e7 2319 * another reduction pass is required.
ashleymills 0:e979170e02e7 2320 */
ashleymills 0:e979170e02e7 2321 top:
ashleymills 0:e979170e02e7 2322 /* aliases for digits */
ashleymills 0:e979170e02e7 2323 /* alias for lower half of x */
ashleymills 0:e979170e02e7 2324 tmpx1 = x->dp;
ashleymills 0:e979170e02e7 2325
ashleymills 0:e979170e02e7 2326 /* alias for upper half of x, or x/B**m */
ashleymills 0:e979170e02e7 2327 tmpx2 = x->dp + m;
ashleymills 0:e979170e02e7 2328
ashleymills 0:e979170e02e7 2329 /* set carry to zero */
ashleymills 0:e979170e02e7 2330 mu = 0;
ashleymills 0:e979170e02e7 2331
ashleymills 0:e979170e02e7 2332 /* compute (x mod B**m) + k * [x/B**m] inline and inplace */
ashleymills 0:e979170e02e7 2333 for (i = 0; i < m; i++) {
ashleymills 0:e979170e02e7 2334 r = ((mp_word)*tmpx2++) * ((mp_word)k) + *tmpx1 + mu;
ashleymills 0:e979170e02e7 2335 *tmpx1++ = (mp_digit)(r & MP_MASK);
ashleymills 0:e979170e02e7 2336 mu = (mp_digit)(r >> ((mp_word)DIGIT_BIT));
ashleymills 0:e979170e02e7 2337 }
ashleymills 0:e979170e02e7 2338
ashleymills 0:e979170e02e7 2339 /* set final carry */
ashleymills 0:e979170e02e7 2340 *tmpx1++ = mu;
ashleymills 0:e979170e02e7 2341
ashleymills 0:e979170e02e7 2342 /* zero words above m */
ashleymills 0:e979170e02e7 2343 for (i = m + 1; i < x->used; i++) {
ashleymills 0:e979170e02e7 2344 *tmpx1++ = 0;
ashleymills 0:e979170e02e7 2345 }
ashleymills 0:e979170e02e7 2346
ashleymills 0:e979170e02e7 2347 /* clamp, sub and return */
ashleymills 0:e979170e02e7 2348 mp_clamp (x);
ashleymills 0:e979170e02e7 2349
ashleymills 0:e979170e02e7 2350 /* if x >= n then subtract and reduce again
ashleymills 0:e979170e02e7 2351 * Each successive "recursion" makes the input smaller and smaller.
ashleymills 0:e979170e02e7 2352 */
ashleymills 0:e979170e02e7 2353 if (mp_cmp_mag (x, n) != MP_LT) {
ashleymills 0:e979170e02e7 2354 s_mp_sub(x, n, x);
ashleymills 0:e979170e02e7 2355 goto top;
ashleymills 0:e979170e02e7 2356 }
ashleymills 0:e979170e02e7 2357 return MP_OKAY;
ashleymills 0:e979170e02e7 2358 }
ashleymills 0:e979170e02e7 2359
ashleymills 0:e979170e02e7 2360
ashleymills 0:e979170e02e7 2361 /* reduces a modulo n where n is of the form 2**p - d */
ashleymills 0:e979170e02e7 2362 int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d)
ashleymills 0:e979170e02e7 2363 {
ashleymills 0:e979170e02e7 2364 mp_int q;
ashleymills 0:e979170e02e7 2365 int p, res;
ashleymills 0:e979170e02e7 2366
ashleymills 0:e979170e02e7 2367 if ((res = mp_init(&q)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2368 return res;
ashleymills 0:e979170e02e7 2369 }
ashleymills 0:e979170e02e7 2370
ashleymills 0:e979170e02e7 2371 p = mp_count_bits(n);
ashleymills 0:e979170e02e7 2372 top:
ashleymills 0:e979170e02e7 2373 /* q = a/2**p, a = a mod 2**p */
ashleymills 0:e979170e02e7 2374 if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2375 goto ERR;
ashleymills 0:e979170e02e7 2376 }
ashleymills 0:e979170e02e7 2377
ashleymills 0:e979170e02e7 2378 if (d != 1) {
ashleymills 0:e979170e02e7 2379 /* q = q * d */
ashleymills 0:e979170e02e7 2380 if ((res = mp_mul_d(&q, d, &q)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2381 goto ERR;
ashleymills 0:e979170e02e7 2382 }
ashleymills 0:e979170e02e7 2383 }
ashleymills 0:e979170e02e7 2384
ashleymills 0:e979170e02e7 2385 /* a = a + q */
ashleymills 0:e979170e02e7 2386 if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2387 goto ERR;
ashleymills 0:e979170e02e7 2388 }
ashleymills 0:e979170e02e7 2389
ashleymills 0:e979170e02e7 2390 if (mp_cmp_mag(a, n) != MP_LT) {
ashleymills 0:e979170e02e7 2391 s_mp_sub(a, n, a);
ashleymills 0:e979170e02e7 2392 goto top;
ashleymills 0:e979170e02e7 2393 }
ashleymills 0:e979170e02e7 2394
ashleymills 0:e979170e02e7 2395 ERR:
ashleymills 0:e979170e02e7 2396 mp_clear(&q);
ashleymills 0:e979170e02e7 2397 return res;
ashleymills 0:e979170e02e7 2398 }
ashleymills 0:e979170e02e7 2399
ashleymills 0:e979170e02e7 2400
ashleymills 0:e979170e02e7 2401 /* determines the setup value */
ashleymills 0:e979170e02e7 2402 int mp_reduce_2k_setup(mp_int *a, mp_digit *d)
ashleymills 0:e979170e02e7 2403 {
ashleymills 0:e979170e02e7 2404 int res, p;
ashleymills 0:e979170e02e7 2405 mp_int tmp;
ashleymills 0:e979170e02e7 2406
ashleymills 0:e979170e02e7 2407 if ((res = mp_init(&tmp)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2408 return res;
ashleymills 0:e979170e02e7 2409 }
ashleymills 0:e979170e02e7 2410
ashleymills 0:e979170e02e7 2411 p = mp_count_bits(a);
ashleymills 0:e979170e02e7 2412 if ((res = mp_2expt(&tmp, p)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2413 mp_clear(&tmp);
ashleymills 0:e979170e02e7 2414 return res;
ashleymills 0:e979170e02e7 2415 }
ashleymills 0:e979170e02e7 2416
ashleymills 0:e979170e02e7 2417 if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2418 mp_clear(&tmp);
ashleymills 0:e979170e02e7 2419 return res;
ashleymills 0:e979170e02e7 2420 }
ashleymills 0:e979170e02e7 2421
ashleymills 0:e979170e02e7 2422 *d = tmp.dp[0];
ashleymills 0:e979170e02e7 2423 mp_clear(&tmp);
ashleymills 0:e979170e02e7 2424 return MP_OKAY;
ashleymills 0:e979170e02e7 2425 }
ashleymills 0:e979170e02e7 2426
ashleymills 0:e979170e02e7 2427
ashleymills 0:e979170e02e7 2428 /* computes a = 2**b
ashleymills 0:e979170e02e7 2429 *
ashleymills 0:e979170e02e7 2430 * Simple algorithm which zeroes the int, grows it then just sets one bit
ashleymills 0:e979170e02e7 2431 * as required.
ashleymills 0:e979170e02e7 2432 */
ashleymills 0:e979170e02e7 2433 int
ashleymills 0:e979170e02e7 2434 mp_2expt (mp_int * a, int b)
ashleymills 0:e979170e02e7 2435 {
ashleymills 0:e979170e02e7 2436 int res;
ashleymills 0:e979170e02e7 2437
ashleymills 0:e979170e02e7 2438 /* zero a as per default */
ashleymills 0:e979170e02e7 2439 mp_zero (a);
ashleymills 0:e979170e02e7 2440
ashleymills 0:e979170e02e7 2441 /* grow a to accomodate the single bit */
ashleymills 0:e979170e02e7 2442 if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2443 return res;
ashleymills 0:e979170e02e7 2444 }
ashleymills 0:e979170e02e7 2445
ashleymills 0:e979170e02e7 2446 /* set the used count of where the bit will go */
ashleymills 0:e979170e02e7 2447 a->used = b / DIGIT_BIT + 1;
ashleymills 0:e979170e02e7 2448
ashleymills 0:e979170e02e7 2449 /* put the single bit in its place */
ashleymills 0:e979170e02e7 2450 a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT);
ashleymills 0:e979170e02e7 2451
ashleymills 0:e979170e02e7 2452 return MP_OKAY;
ashleymills 0:e979170e02e7 2453 }
ashleymills 0:e979170e02e7 2454
ashleymills 0:e979170e02e7 2455
ashleymills 0:e979170e02e7 2456 /* multiply by a digit */
ashleymills 0:e979170e02e7 2457 int
ashleymills 0:e979170e02e7 2458 mp_mul_d (mp_int * a, mp_digit b, mp_int * c)
ashleymills 0:e979170e02e7 2459 {
ashleymills 0:e979170e02e7 2460 mp_digit u, *tmpa, *tmpc;
ashleymills 0:e979170e02e7 2461 mp_word r;
ashleymills 0:e979170e02e7 2462 int ix, res, olduse;
ashleymills 0:e979170e02e7 2463
ashleymills 0:e979170e02e7 2464 /* make sure c is big enough to hold a*b */
ashleymills 0:e979170e02e7 2465 if (c->alloc < a->used + 1) {
ashleymills 0:e979170e02e7 2466 if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2467 return res;
ashleymills 0:e979170e02e7 2468 }
ashleymills 0:e979170e02e7 2469 }
ashleymills 0:e979170e02e7 2470
ashleymills 0:e979170e02e7 2471 /* get the original destinations used count */
ashleymills 0:e979170e02e7 2472 olduse = c->used;
ashleymills 0:e979170e02e7 2473
ashleymills 0:e979170e02e7 2474 /* set the sign */
ashleymills 0:e979170e02e7 2475 c->sign = a->sign;
ashleymills 0:e979170e02e7 2476
ashleymills 0:e979170e02e7 2477 /* alias for a->dp [source] */
ashleymills 0:e979170e02e7 2478 tmpa = a->dp;
ashleymills 0:e979170e02e7 2479
ashleymills 0:e979170e02e7 2480 /* alias for c->dp [dest] */
ashleymills 0:e979170e02e7 2481 tmpc = c->dp;
ashleymills 0:e979170e02e7 2482
ashleymills 0:e979170e02e7 2483 /* zero carry */
ashleymills 0:e979170e02e7 2484 u = 0;
ashleymills 0:e979170e02e7 2485
ashleymills 0:e979170e02e7 2486 /* compute columns */
ashleymills 0:e979170e02e7 2487 for (ix = 0; ix < a->used; ix++) {
ashleymills 0:e979170e02e7 2488 /* compute product and carry sum for this term */
ashleymills 0:e979170e02e7 2489 r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
ashleymills 0:e979170e02e7 2490
ashleymills 0:e979170e02e7 2491 /* mask off higher bits to get a single digit */
ashleymills 0:e979170e02e7 2492 *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
ashleymills 0:e979170e02e7 2493
ashleymills 0:e979170e02e7 2494 /* send carry into next iteration */
ashleymills 0:e979170e02e7 2495 u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
ashleymills 0:e979170e02e7 2496 }
ashleymills 0:e979170e02e7 2497
ashleymills 0:e979170e02e7 2498 /* store final carry [if any] and increment ix offset */
ashleymills 0:e979170e02e7 2499 *tmpc++ = u;
ashleymills 0:e979170e02e7 2500 ++ix;
ashleymills 0:e979170e02e7 2501
ashleymills 0:e979170e02e7 2502 /* now zero digits above the top */
ashleymills 0:e979170e02e7 2503 while (ix++ < olduse) {
ashleymills 0:e979170e02e7 2504 *tmpc++ = 0;
ashleymills 0:e979170e02e7 2505 }
ashleymills 0:e979170e02e7 2506
ashleymills 0:e979170e02e7 2507 /* set used count */
ashleymills 0:e979170e02e7 2508 c->used = a->used + 1;
ashleymills 0:e979170e02e7 2509 mp_clamp(c);
ashleymills 0:e979170e02e7 2510
ashleymills 0:e979170e02e7 2511 return MP_OKAY;
ashleymills 0:e979170e02e7 2512 }
ashleymills 0:e979170e02e7 2513
ashleymills 0:e979170e02e7 2514
ashleymills 0:e979170e02e7 2515 /* d = a * b (mod c) */
ashleymills 0:e979170e02e7 2516 int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
ashleymills 0:e979170e02e7 2517 {
ashleymills 0:e979170e02e7 2518 int res;
ashleymills 0:e979170e02e7 2519 mp_int t;
ashleymills 0:e979170e02e7 2520
ashleymills 0:e979170e02e7 2521 if ((res = mp_init (&t)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2522 return res;
ashleymills 0:e979170e02e7 2523 }
ashleymills 0:e979170e02e7 2524
ashleymills 0:e979170e02e7 2525 if ((res = mp_mul (a, b, &t)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2526 mp_clear (&t);
ashleymills 0:e979170e02e7 2527 return res;
ashleymills 0:e979170e02e7 2528 }
ashleymills 0:e979170e02e7 2529 res = mp_mod (&t, c, d);
ashleymills 0:e979170e02e7 2530 mp_clear (&t);
ashleymills 0:e979170e02e7 2531 return res;
ashleymills 0:e979170e02e7 2532 }
ashleymills 0:e979170e02e7 2533
ashleymills 0:e979170e02e7 2534
ashleymills 0:e979170e02e7 2535 /* computes b = a*a */
ashleymills 0:e979170e02e7 2536 int
ashleymills 0:e979170e02e7 2537 mp_sqr (mp_int * a, mp_int * b)
ashleymills 0:e979170e02e7 2538 {
ashleymills 0:e979170e02e7 2539 int res;
ashleymills 0:e979170e02e7 2540
ashleymills 0:e979170e02e7 2541 {
ashleymills 0:e979170e02e7 2542 #ifdef BN_FAST_S_MP_SQR_C
ashleymills 0:e979170e02e7 2543 /* can we use the fast comba multiplier? */
ashleymills 0:e979170e02e7 2544 if ((a->used * 2 + 1) < MP_WARRAY &&
ashleymills 0:e979170e02e7 2545 a->used <
ashleymills 0:e979170e02e7 2546 (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
ashleymills 0:e979170e02e7 2547 res = fast_s_mp_sqr (a, b);
ashleymills 0:e979170e02e7 2548 } else
ashleymills 0:e979170e02e7 2549 #endif
ashleymills 0:e979170e02e7 2550 #ifdef BN_S_MP_SQR_C
ashleymills 0:e979170e02e7 2551 res = s_mp_sqr (a, b);
ashleymills 0:e979170e02e7 2552 #else
ashleymills 0:e979170e02e7 2553 res = MP_VAL;
ashleymills 0:e979170e02e7 2554 #endif
ashleymills 0:e979170e02e7 2555 }
ashleymills 0:e979170e02e7 2556 b->sign = MP_ZPOS;
ashleymills 0:e979170e02e7 2557 return res;
ashleymills 0:e979170e02e7 2558 }
ashleymills 0:e979170e02e7 2559
ashleymills 0:e979170e02e7 2560
ashleymills 0:e979170e02e7 2561 /* high level multiplication (handles sign) */
ashleymills 0:e979170e02e7 2562 int mp_mul (mp_int * a, mp_int * b, mp_int * c)
ashleymills 0:e979170e02e7 2563 {
ashleymills 0:e979170e02e7 2564 int res, neg;
ashleymills 0:e979170e02e7 2565 neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
ashleymills 0:e979170e02e7 2566
ashleymills 0:e979170e02e7 2567 {
ashleymills 0:e979170e02e7 2568 /* can we use the fast multiplier?
ashleymills 0:e979170e02e7 2569 *
ashleymills 0:e979170e02e7 2570 * The fast multiplier can be used if the output will
ashleymills 0:e979170e02e7 2571 * have less than MP_WARRAY digits and the number of
ashleymills 0:e979170e02e7 2572 * digits won't affect carry propagation
ashleymills 0:e979170e02e7 2573 */
ashleymills 0:e979170e02e7 2574 int digs = a->used + b->used + 1;
ashleymills 0:e979170e02e7 2575
ashleymills 0:e979170e02e7 2576 #ifdef BN_FAST_S_MP_MUL_DIGS_C
ashleymills 0:e979170e02e7 2577 if ((digs < MP_WARRAY) &&
ashleymills 0:e979170e02e7 2578 MIN(a->used, b->used) <=
ashleymills 0:e979170e02e7 2579 (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
ashleymills 0:e979170e02e7 2580 res = fast_s_mp_mul_digs (a, b, c, digs);
ashleymills 0:e979170e02e7 2581 } else
ashleymills 0:e979170e02e7 2582 #endif
ashleymills 0:e979170e02e7 2583 #ifdef BN_S_MP_MUL_DIGS_C
ashleymills 0:e979170e02e7 2584 res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
ashleymills 0:e979170e02e7 2585 #else
ashleymills 0:e979170e02e7 2586 res = MP_VAL;
ashleymills 0:e979170e02e7 2587 #endif
ashleymills 0:e979170e02e7 2588
ashleymills 0:e979170e02e7 2589 }
ashleymills 0:e979170e02e7 2590 c->sign = (c->used > 0) ? neg : MP_ZPOS;
ashleymills 0:e979170e02e7 2591 return res;
ashleymills 0:e979170e02e7 2592 }
ashleymills 0:e979170e02e7 2593
ashleymills 0:e979170e02e7 2594
ashleymills 0:e979170e02e7 2595 /* b = a*2 */
ashleymills 0:e979170e02e7 2596 int mp_mul_2(mp_int * a, mp_int * b)
ashleymills 0:e979170e02e7 2597 {
ashleymills 0:e979170e02e7 2598 int x, res, oldused;
ashleymills 0:e979170e02e7 2599
ashleymills 0:e979170e02e7 2600 /* grow to accomodate result */
ashleymills 0:e979170e02e7 2601 if (b->alloc < a->used + 1) {
ashleymills 0:e979170e02e7 2602 if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2603 return res;
ashleymills 0:e979170e02e7 2604 }
ashleymills 0:e979170e02e7 2605 }
ashleymills 0:e979170e02e7 2606
ashleymills 0:e979170e02e7 2607 oldused = b->used;
ashleymills 0:e979170e02e7 2608 b->used = a->used;
ashleymills 0:e979170e02e7 2609
ashleymills 0:e979170e02e7 2610 {
ashleymills 0:e979170e02e7 2611 register mp_digit r, rr, *tmpa, *tmpb;
ashleymills 0:e979170e02e7 2612
ashleymills 0:e979170e02e7 2613 /* alias for source */
ashleymills 0:e979170e02e7 2614 tmpa = a->dp;
ashleymills 0:e979170e02e7 2615
ashleymills 0:e979170e02e7 2616 /* alias for dest */
ashleymills 0:e979170e02e7 2617 tmpb = b->dp;
ashleymills 0:e979170e02e7 2618
ashleymills 0:e979170e02e7 2619 /* carry */
ashleymills 0:e979170e02e7 2620 r = 0;
ashleymills 0:e979170e02e7 2621 for (x = 0; x < a->used; x++) {
ashleymills 0:e979170e02e7 2622
ashleymills 0:e979170e02e7 2623 /* get what will be the *next* carry bit from the
ashleymills 0:e979170e02e7 2624 * MSB of the current digit
ashleymills 0:e979170e02e7 2625 */
ashleymills 0:e979170e02e7 2626 rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
ashleymills 0:e979170e02e7 2627
ashleymills 0:e979170e02e7 2628 /* now shift up this digit, add in the carry [from the previous] */
ashleymills 0:e979170e02e7 2629 *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
ashleymills 0:e979170e02e7 2630
ashleymills 0:e979170e02e7 2631 /* copy the carry that would be from the source
ashleymills 0:e979170e02e7 2632 * digit into the next iteration
ashleymills 0:e979170e02e7 2633 */
ashleymills 0:e979170e02e7 2634 r = rr;
ashleymills 0:e979170e02e7 2635 }
ashleymills 0:e979170e02e7 2636
ashleymills 0:e979170e02e7 2637 /* new leading digit? */
ashleymills 0:e979170e02e7 2638 if (r != 0) {
ashleymills 0:e979170e02e7 2639 /* add a MSB which is always 1 at this point */
ashleymills 0:e979170e02e7 2640 *tmpb = 1;
ashleymills 0:e979170e02e7 2641 ++(b->used);
ashleymills 0:e979170e02e7 2642 }
ashleymills 0:e979170e02e7 2643
ashleymills 0:e979170e02e7 2644 /* now zero any excess digits on the destination
ashleymills 0:e979170e02e7 2645 * that we didn't write to
ashleymills 0:e979170e02e7 2646 */
ashleymills 0:e979170e02e7 2647 tmpb = b->dp + b->used;
ashleymills 0:e979170e02e7 2648 for (x = b->used; x < oldused; x++) {
ashleymills 0:e979170e02e7 2649 *tmpb++ = 0;
ashleymills 0:e979170e02e7 2650 }
ashleymills 0:e979170e02e7 2651 }
ashleymills 0:e979170e02e7 2652 b->sign = a->sign;
ashleymills 0:e979170e02e7 2653 return MP_OKAY;
ashleymills 0:e979170e02e7 2654 }
ashleymills 0:e979170e02e7 2655
ashleymills 0:e979170e02e7 2656
ashleymills 0:e979170e02e7 2657 /* divide by three (based on routine from MPI and the GMP manual) */
ashleymills 0:e979170e02e7 2658 int
ashleymills 0:e979170e02e7 2659 mp_div_3 (mp_int * a, mp_int *c, mp_digit * d)
ashleymills 0:e979170e02e7 2660 {
ashleymills 0:e979170e02e7 2661 mp_int q;
ashleymills 0:e979170e02e7 2662 mp_word w, t;
ashleymills 0:e979170e02e7 2663 mp_digit b;
ashleymills 0:e979170e02e7 2664 int res, ix;
ashleymills 0:e979170e02e7 2665
ashleymills 0:e979170e02e7 2666 /* b = 2**DIGIT_BIT / 3 */
ashleymills 0:e979170e02e7 2667 b = (((mp_word)1) << ((mp_word)DIGIT_BIT)) / ((mp_word)3);
ashleymills 0:e979170e02e7 2668
ashleymills 0:e979170e02e7 2669 if ((res = mp_init_size(&q, a->used)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2670 return res;
ashleymills 0:e979170e02e7 2671 }
ashleymills 0:e979170e02e7 2672
ashleymills 0:e979170e02e7 2673 q.used = a->used;
ashleymills 0:e979170e02e7 2674 q.sign = a->sign;
ashleymills 0:e979170e02e7 2675 w = 0;
ashleymills 0:e979170e02e7 2676 for (ix = a->used - 1; ix >= 0; ix--) {
ashleymills 0:e979170e02e7 2677 w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]);
ashleymills 0:e979170e02e7 2678
ashleymills 0:e979170e02e7 2679 if (w >= 3) {
ashleymills 0:e979170e02e7 2680 /* multiply w by [1/3] */
ashleymills 0:e979170e02e7 2681 t = (w * ((mp_word)b)) >> ((mp_word)DIGIT_BIT);
ashleymills 0:e979170e02e7 2682
ashleymills 0:e979170e02e7 2683 /* now subtract 3 * [w/3] from w, to get the remainder */
ashleymills 0:e979170e02e7 2684 w -= t+t+t;
ashleymills 0:e979170e02e7 2685
ashleymills 0:e979170e02e7 2686 /* fixup the remainder as required since
ashleymills 0:e979170e02e7 2687 * the optimization is not exact.
ashleymills 0:e979170e02e7 2688 */
ashleymills 0:e979170e02e7 2689 while (w >= 3) {
ashleymills 0:e979170e02e7 2690 t += 1;
ashleymills 0:e979170e02e7 2691 w -= 3;
ashleymills 0:e979170e02e7 2692 }
ashleymills 0:e979170e02e7 2693 } else {
ashleymills 0:e979170e02e7 2694 t = 0;
ashleymills 0:e979170e02e7 2695 }
ashleymills 0:e979170e02e7 2696 q.dp[ix] = (mp_digit)t;
ashleymills 0:e979170e02e7 2697 }
ashleymills 0:e979170e02e7 2698
ashleymills 0:e979170e02e7 2699 /* [optional] store the remainder */
ashleymills 0:e979170e02e7 2700 if (d != NULL) {
ashleymills 0:e979170e02e7 2701 *d = (mp_digit)w;
ashleymills 0:e979170e02e7 2702 }
ashleymills 0:e979170e02e7 2703
ashleymills 0:e979170e02e7 2704 /* [optional] store the quotient */
ashleymills 0:e979170e02e7 2705 if (c != NULL) {
ashleymills 0:e979170e02e7 2706 mp_clamp(&q);
ashleymills 0:e979170e02e7 2707 mp_exch(&q, c);
ashleymills 0:e979170e02e7 2708 }
ashleymills 0:e979170e02e7 2709 mp_clear(&q);
ashleymills 0:e979170e02e7 2710
ashleymills 0:e979170e02e7 2711 return res;
ashleymills 0:e979170e02e7 2712 }
ashleymills 0:e979170e02e7 2713
ashleymills 0:e979170e02e7 2714
ashleymills 0:e979170e02e7 2715 /* init an mp_init for a given size */
ashleymills 0:e979170e02e7 2716 int mp_init_size (mp_int * a, int size)
ashleymills 0:e979170e02e7 2717 {
ashleymills 0:e979170e02e7 2718 int x;
ashleymills 0:e979170e02e7 2719
ashleymills 0:e979170e02e7 2720 /* pad size so there are always extra digits */
ashleymills 0:e979170e02e7 2721 size += (MP_PREC * 2) - (size % MP_PREC);
ashleymills 0:e979170e02e7 2722
ashleymills 0:e979170e02e7 2723 /* alloc mem */
ashleymills 0:e979170e02e7 2724 a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size, 0,
ashleymills 0:e979170e02e7 2725 DYNAMIC_TYPE_BIGINT);
ashleymills 0:e979170e02e7 2726 if (a->dp == NULL) {
ashleymills 0:e979170e02e7 2727 return MP_MEM;
ashleymills 0:e979170e02e7 2728 }
ashleymills 0:e979170e02e7 2729
ashleymills 0:e979170e02e7 2730 /* set the members */
ashleymills 0:e979170e02e7 2731 a->used = 0;
ashleymills 0:e979170e02e7 2732 a->alloc = size;
ashleymills 0:e979170e02e7 2733 a->sign = MP_ZPOS;
ashleymills 0:e979170e02e7 2734
ashleymills 0:e979170e02e7 2735 /* zero the digits */
ashleymills 0:e979170e02e7 2736 for (x = 0; x < size; x++) {
ashleymills 0:e979170e02e7 2737 a->dp[x] = 0;
ashleymills 0:e979170e02e7 2738 }
ashleymills 0:e979170e02e7 2739
ashleymills 0:e979170e02e7 2740 return MP_OKAY;
ashleymills 0:e979170e02e7 2741 }
ashleymills 0:e979170e02e7 2742
ashleymills 0:e979170e02e7 2743
ashleymills 0:e979170e02e7 2744 /* the jist of squaring...
ashleymills 0:e979170e02e7 2745 * you do like mult except the offset of the tmpx [one that
ashleymills 0:e979170e02e7 2746 * starts closer to zero] can't equal the offset of tmpy.
ashleymills 0:e979170e02e7 2747 * So basically you set up iy like before then you min it with
ashleymills 0:e979170e02e7 2748 * (ty-tx) so that it never happens. You double all those
ashleymills 0:e979170e02e7 2749 * you add in the inner loop
ashleymills 0:e979170e02e7 2750
ashleymills 0:e979170e02e7 2751 After that loop you do the squares and add them in.
ashleymills 0:e979170e02e7 2752 */
ashleymills 0:e979170e02e7 2753
ashleymills 0:e979170e02e7 2754 int fast_s_mp_sqr (mp_int * a, mp_int * b)
ashleymills 0:e979170e02e7 2755 {
ashleymills 0:e979170e02e7 2756 int olduse, res, pa, ix, iz;
ashleymills 0:e979170e02e7 2757 #ifdef CYASSL_SMALL_STACK
ashleymills 0:e979170e02e7 2758 mp_digit* W; /* uses dynamic memory and slower */
ashleymills 0:e979170e02e7 2759 #else
ashleymills 0:e979170e02e7 2760 mp_digit W[MP_WARRAY];
ashleymills 0:e979170e02e7 2761 #endif
ashleymills 0:e979170e02e7 2762 mp_digit *tmpx;
ashleymills 0:e979170e02e7 2763 mp_word W1;
ashleymills 0:e979170e02e7 2764
ashleymills 0:e979170e02e7 2765 /* grow the destination as required */
ashleymills 0:e979170e02e7 2766 pa = a->used + a->used;
ashleymills 0:e979170e02e7 2767 if (b->alloc < pa) {
ashleymills 0:e979170e02e7 2768 if ((res = mp_grow (b, pa)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2769 return res;
ashleymills 0:e979170e02e7 2770 }
ashleymills 0:e979170e02e7 2771 }
ashleymills 0:e979170e02e7 2772
ashleymills 0:e979170e02e7 2773 if (pa > MP_WARRAY)
ashleymills 0:e979170e02e7 2774 return MP_RANGE; /* TAO range check */
ashleymills 0:e979170e02e7 2775
ashleymills 0:e979170e02e7 2776 #ifdef CYASSL_SMALL_STACK
ashleymills 0:e979170e02e7 2777 W = (mp_digit*)XMALLOC(sizeof(mp_digit) * MP_WARRAY, 0, DYNAMIC_TYPE_BIGINT);
ashleymills 0:e979170e02e7 2778 if (W == NULL)
ashleymills 0:e979170e02e7 2779 return MP_MEM;
ashleymills 0:e979170e02e7 2780 #endif
ashleymills 0:e979170e02e7 2781
ashleymills 0:e979170e02e7 2782 /* number of output digits to produce */
ashleymills 0:e979170e02e7 2783 W1 = 0;
ashleymills 0:e979170e02e7 2784 for (ix = 0; ix < pa; ix++) {
ashleymills 0:e979170e02e7 2785 int tx, ty, iy;
ashleymills 0:e979170e02e7 2786 mp_word _W;
ashleymills 0:e979170e02e7 2787 mp_digit *tmpy;
ashleymills 0:e979170e02e7 2788
ashleymills 0:e979170e02e7 2789 /* clear counter */
ashleymills 0:e979170e02e7 2790 _W = 0;
ashleymills 0:e979170e02e7 2791
ashleymills 0:e979170e02e7 2792 /* get offsets into the two bignums */
ashleymills 0:e979170e02e7 2793 ty = MIN(a->used-1, ix);
ashleymills 0:e979170e02e7 2794 tx = ix - ty;
ashleymills 0:e979170e02e7 2795
ashleymills 0:e979170e02e7 2796 /* setup temp aliases */
ashleymills 0:e979170e02e7 2797 tmpx = a->dp + tx;
ashleymills 0:e979170e02e7 2798 tmpy = a->dp + ty;
ashleymills 0:e979170e02e7 2799
ashleymills 0:e979170e02e7 2800 /* this is the number of times the loop will iterrate, essentially
ashleymills 0:e979170e02e7 2801 while (tx++ < a->used && ty-- >= 0) { ... }
ashleymills 0:e979170e02e7 2802 */
ashleymills 0:e979170e02e7 2803 iy = MIN(a->used-tx, ty+1);
ashleymills 0:e979170e02e7 2804
ashleymills 0:e979170e02e7 2805 /* now for squaring tx can never equal ty
ashleymills 0:e979170e02e7 2806 * we halve the distance since they approach at a rate of 2x
ashleymills 0:e979170e02e7 2807 * and we have to round because odd cases need to be executed
ashleymills 0:e979170e02e7 2808 */
ashleymills 0:e979170e02e7 2809 iy = MIN(iy, (ty-tx+1)>>1);
ashleymills 0:e979170e02e7 2810
ashleymills 0:e979170e02e7 2811 /* execute loop */
ashleymills 0:e979170e02e7 2812 for (iz = 0; iz < iy; iz++) {
ashleymills 0:e979170e02e7 2813 _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
ashleymills 0:e979170e02e7 2814 }
ashleymills 0:e979170e02e7 2815
ashleymills 0:e979170e02e7 2816 /* double the inner product and add carry */
ashleymills 0:e979170e02e7 2817 _W = _W + _W + W1;
ashleymills 0:e979170e02e7 2818
ashleymills 0:e979170e02e7 2819 /* even columns have the square term in them */
ashleymills 0:e979170e02e7 2820 if ((ix&1) == 0) {
ashleymills 0:e979170e02e7 2821 _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
ashleymills 0:e979170e02e7 2822 }
ashleymills 0:e979170e02e7 2823
ashleymills 0:e979170e02e7 2824 /* store it */
ashleymills 0:e979170e02e7 2825 W[ix] = (mp_digit)(_W & MP_MASK);
ashleymills 0:e979170e02e7 2826
ashleymills 0:e979170e02e7 2827 /* make next carry */
ashleymills 0:e979170e02e7 2828 W1 = _W >> ((mp_word)DIGIT_BIT);
ashleymills 0:e979170e02e7 2829 }
ashleymills 0:e979170e02e7 2830
ashleymills 0:e979170e02e7 2831 /* setup dest */
ashleymills 0:e979170e02e7 2832 olduse = b->used;
ashleymills 0:e979170e02e7 2833 b->used = a->used+a->used;
ashleymills 0:e979170e02e7 2834
ashleymills 0:e979170e02e7 2835 {
ashleymills 0:e979170e02e7 2836 mp_digit *tmpb;
ashleymills 0:e979170e02e7 2837 tmpb = b->dp;
ashleymills 0:e979170e02e7 2838 for (ix = 0; ix < pa; ix++) {
ashleymills 0:e979170e02e7 2839 *tmpb++ = W[ix] & MP_MASK;
ashleymills 0:e979170e02e7 2840 }
ashleymills 0:e979170e02e7 2841
ashleymills 0:e979170e02e7 2842 /* clear unused digits [that existed in the old copy of c] */
ashleymills 0:e979170e02e7 2843 for (; ix < olduse; ix++) {
ashleymills 0:e979170e02e7 2844 *tmpb++ = 0;
ashleymills 0:e979170e02e7 2845 }
ashleymills 0:e979170e02e7 2846 }
ashleymills 0:e979170e02e7 2847 mp_clamp (b);
ashleymills 0:e979170e02e7 2848
ashleymills 0:e979170e02e7 2849 #ifdef CYASSL_SMALL_STACK
ashleymills 0:e979170e02e7 2850 XFREE(W, 0, DYNAMIC_TYPE_BIGINT);
ashleymills 0:e979170e02e7 2851 #endif
ashleymills 0:e979170e02e7 2852
ashleymills 0:e979170e02e7 2853 return MP_OKAY;
ashleymills 0:e979170e02e7 2854 }
ashleymills 0:e979170e02e7 2855
ashleymills 0:e979170e02e7 2856
ashleymills 0:e979170e02e7 2857 /* Fast (comba) multiplier
ashleymills 0:e979170e02e7 2858 *
ashleymills 0:e979170e02e7 2859 * This is the fast column-array [comba] multiplier. It is
ashleymills 0:e979170e02e7 2860 * designed to compute the columns of the product first
ashleymills 0:e979170e02e7 2861 * then handle the carries afterwards. This has the effect
ashleymills 0:e979170e02e7 2862 * of making the nested loops that compute the columns very
ashleymills 0:e979170e02e7 2863 * simple and schedulable on super-scalar processors.
ashleymills 0:e979170e02e7 2864 *
ashleymills 0:e979170e02e7 2865 * This has been modified to produce a variable number of
ashleymills 0:e979170e02e7 2866 * digits of output so if say only a half-product is required
ashleymills 0:e979170e02e7 2867 * you don't have to compute the upper half (a feature
ashleymills 0:e979170e02e7 2868 * required for fast Barrett reduction).
ashleymills 0:e979170e02e7 2869 *
ashleymills 0:e979170e02e7 2870 * Based on Algorithm 14.12 on pp.595 of HAC.
ashleymills 0:e979170e02e7 2871 *
ashleymills 0:e979170e02e7 2872 */
ashleymills 0:e979170e02e7 2873 int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
ashleymills 0:e979170e02e7 2874 {
ashleymills 0:e979170e02e7 2875 int olduse, res, pa, ix, iz;
ashleymills 0:e979170e02e7 2876 #ifdef CYASSL_SMALL_STACK
ashleymills 0:e979170e02e7 2877 mp_digit* W; /* uses dynamic memory and slower */
ashleymills 0:e979170e02e7 2878 #else
ashleymills 0:e979170e02e7 2879 mp_digit W[MP_WARRAY];
ashleymills 0:e979170e02e7 2880 #endif
ashleymills 0:e979170e02e7 2881 register mp_word _W;
ashleymills 0:e979170e02e7 2882
ashleymills 0:e979170e02e7 2883 /* grow the destination as required */
ashleymills 0:e979170e02e7 2884 if (c->alloc < digs) {
ashleymills 0:e979170e02e7 2885 if ((res = mp_grow (c, digs)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2886 return res;
ashleymills 0:e979170e02e7 2887 }
ashleymills 0:e979170e02e7 2888 }
ashleymills 0:e979170e02e7 2889
ashleymills 0:e979170e02e7 2890 /* number of output digits to produce */
ashleymills 0:e979170e02e7 2891 pa = MIN(digs, a->used + b->used);
ashleymills 0:e979170e02e7 2892 if (pa > MP_WARRAY)
ashleymills 0:e979170e02e7 2893 return MP_RANGE; /* TAO range check */
ashleymills 0:e979170e02e7 2894
ashleymills 0:e979170e02e7 2895 #ifdef CYASSL_SMALL_STACK
ashleymills 0:e979170e02e7 2896 W = (mp_digit*)XMALLOC(sizeof(mp_digit) * MP_WARRAY, 0, DYNAMIC_TYPE_BIGINT);
ashleymills 0:e979170e02e7 2897 if (W == NULL)
ashleymills 0:e979170e02e7 2898 return MP_MEM;
ashleymills 0:e979170e02e7 2899 #endif
ashleymills 0:e979170e02e7 2900
ashleymills 0:e979170e02e7 2901 /* clear the carry */
ashleymills 0:e979170e02e7 2902 _W = 0;
ashleymills 0:e979170e02e7 2903 for (ix = 0; ix < pa; ix++) {
ashleymills 0:e979170e02e7 2904 int tx, ty;
ashleymills 0:e979170e02e7 2905 int iy;
ashleymills 0:e979170e02e7 2906 mp_digit *tmpx, *tmpy;
ashleymills 0:e979170e02e7 2907
ashleymills 0:e979170e02e7 2908 /* get offsets into the two bignums */
ashleymills 0:e979170e02e7 2909 ty = MIN(b->used-1, ix);
ashleymills 0:e979170e02e7 2910 tx = ix - ty;
ashleymills 0:e979170e02e7 2911
ashleymills 0:e979170e02e7 2912 /* setup temp aliases */
ashleymills 0:e979170e02e7 2913 tmpx = a->dp + tx;
ashleymills 0:e979170e02e7 2914 tmpy = b->dp + ty;
ashleymills 0:e979170e02e7 2915
ashleymills 0:e979170e02e7 2916 /* this is the number of times the loop will iterrate, essentially
ashleymills 0:e979170e02e7 2917 while (tx++ < a->used && ty-- >= 0) { ... }
ashleymills 0:e979170e02e7 2918 */
ashleymills 0:e979170e02e7 2919 iy = MIN(a->used-tx, ty+1);
ashleymills 0:e979170e02e7 2920
ashleymills 0:e979170e02e7 2921 /* execute loop */
ashleymills 0:e979170e02e7 2922 for (iz = 0; iz < iy; ++iz) {
ashleymills 0:e979170e02e7 2923 _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
ashleymills 0:e979170e02e7 2924
ashleymills 0:e979170e02e7 2925 }
ashleymills 0:e979170e02e7 2926
ashleymills 0:e979170e02e7 2927 /* store term */
ashleymills 0:e979170e02e7 2928 W[ix] = ((mp_digit)_W) & MP_MASK;
ashleymills 0:e979170e02e7 2929
ashleymills 0:e979170e02e7 2930 /* make next carry */
ashleymills 0:e979170e02e7 2931 _W = _W >> ((mp_word)DIGIT_BIT);
ashleymills 0:e979170e02e7 2932 }
ashleymills 0:e979170e02e7 2933
ashleymills 0:e979170e02e7 2934 /* setup dest */
ashleymills 0:e979170e02e7 2935 olduse = c->used;
ashleymills 0:e979170e02e7 2936 c->used = pa;
ashleymills 0:e979170e02e7 2937
ashleymills 0:e979170e02e7 2938 {
ashleymills 0:e979170e02e7 2939 register mp_digit *tmpc;
ashleymills 0:e979170e02e7 2940 tmpc = c->dp;
ashleymills 0:e979170e02e7 2941 for (ix = 0; ix < pa+1; ix++) {
ashleymills 0:e979170e02e7 2942 /* now extract the previous digit [below the carry] */
ashleymills 0:e979170e02e7 2943 *tmpc++ = W[ix];
ashleymills 0:e979170e02e7 2944 }
ashleymills 0:e979170e02e7 2945
ashleymills 0:e979170e02e7 2946 /* clear unused digits [that existed in the old copy of c] */
ashleymills 0:e979170e02e7 2947 for (; ix < olduse; ix++) {
ashleymills 0:e979170e02e7 2948 *tmpc++ = 0;
ashleymills 0:e979170e02e7 2949 }
ashleymills 0:e979170e02e7 2950 }
ashleymills 0:e979170e02e7 2951 mp_clamp (c);
ashleymills 0:e979170e02e7 2952
ashleymills 0:e979170e02e7 2953 #ifdef CYASSL_SMALL_STACK
ashleymills 0:e979170e02e7 2954 XFREE(W, 0, DYNAMIC_TYPE_BIGINT);
ashleymills 0:e979170e02e7 2955 #endif
ashleymills 0:e979170e02e7 2956
ashleymills 0:e979170e02e7 2957 return MP_OKAY;
ashleymills 0:e979170e02e7 2958 }
ashleymills 0:e979170e02e7 2959
ashleymills 0:e979170e02e7 2960
ashleymills 0:e979170e02e7 2961 /* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
ashleymills 0:e979170e02e7 2962 int s_mp_sqr (mp_int * a, mp_int * b)
ashleymills 0:e979170e02e7 2963 {
ashleymills 0:e979170e02e7 2964 mp_int t;
ashleymills 0:e979170e02e7 2965 int res, ix, iy, pa;
ashleymills 0:e979170e02e7 2966 mp_word r;
ashleymills 0:e979170e02e7 2967 mp_digit u, tmpx, *tmpt;
ashleymills 0:e979170e02e7 2968
ashleymills 0:e979170e02e7 2969 pa = a->used;
ashleymills 0:e979170e02e7 2970 if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) {
ashleymills 0:e979170e02e7 2971 return res;
ashleymills 0:e979170e02e7 2972 }
ashleymills 0:e979170e02e7 2973
ashleymills 0:e979170e02e7 2974 /* default used is maximum possible size */
ashleymills 0:e979170e02e7 2975 t.used = 2*pa + 1;
ashleymills 0:e979170e02e7 2976
ashleymills 0:e979170e02e7 2977 for (ix = 0; ix < pa; ix++) {
ashleymills 0:e979170e02e7 2978 /* first calculate the digit at 2*ix */
ashleymills 0:e979170e02e7 2979 /* calculate double precision result */
ashleymills 0:e979170e02e7 2980 r = ((mp_word) t.dp[2*ix]) +
ashleymills 0:e979170e02e7 2981 ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]);
ashleymills 0:e979170e02e7 2982
ashleymills 0:e979170e02e7 2983 /* store lower part in result */
ashleymills 0:e979170e02e7 2984 t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK));
ashleymills 0:e979170e02e7 2985
ashleymills 0:e979170e02e7 2986 /* get the carry */
ashleymills 0:e979170e02e7 2987 u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
ashleymills 0:e979170e02e7 2988
ashleymills 0:e979170e02e7 2989 /* left hand side of A[ix] * A[iy] */
ashleymills 0:e979170e02e7 2990 tmpx = a->dp[ix];
ashleymills 0:e979170e02e7 2991
ashleymills 0:e979170e02e7 2992 /* alias for where to store the results */
ashleymills 0:e979170e02e7 2993 tmpt = t.dp + (2*ix + 1);
ashleymills 0:e979170e02e7 2994
ashleymills 0:e979170e02e7 2995 for (iy = ix + 1; iy < pa; iy++) {
ashleymills 0:e979170e02e7 2996 /* first calculate the product */
ashleymills 0:e979170e02e7 2997 r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
ashleymills 0:e979170e02e7 2998
ashleymills 0:e979170e02e7 2999 /* now calculate the double precision result, note we use
ashleymills 0:e979170e02e7 3000 * addition instead of *2 since it's easier to optimize
ashleymills 0:e979170e02e7 3001 */
ashleymills 0:e979170e02e7 3002 r = ((mp_word) *tmpt) + r + r + ((mp_word) u);
ashleymills 0:e979170e02e7 3003
ashleymills 0:e979170e02e7 3004 /* store lower part */
ashleymills 0:e979170e02e7 3005 *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
ashleymills 0:e979170e02e7 3006
ashleymills 0:e979170e02e7 3007 /* get carry */
ashleymills 0:e979170e02e7 3008 u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
ashleymills 0:e979170e02e7 3009 }
ashleymills 0:e979170e02e7 3010 /* propagate upwards */
ashleymills 0:e979170e02e7 3011 while (u != ((mp_digit) 0)) {
ashleymills 0:e979170e02e7 3012 r = ((mp_word) *tmpt) + ((mp_word) u);
ashleymills 0:e979170e02e7 3013 *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
ashleymills 0:e979170e02e7 3014 u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
ashleymills 0:e979170e02e7 3015 }
ashleymills 0:e979170e02e7 3016 }
ashleymills 0:e979170e02e7 3017
ashleymills 0:e979170e02e7 3018 mp_clamp (&t);
ashleymills 0:e979170e02e7 3019 mp_exch (&t, b);
ashleymills 0:e979170e02e7 3020 mp_clear (&t);
ashleymills 0:e979170e02e7 3021 return MP_OKAY;
ashleymills 0:e979170e02e7 3022 }
ashleymills 0:e979170e02e7 3023
ashleymills 0:e979170e02e7 3024
ashleymills 0:e979170e02e7 3025 /* multiplies |a| * |b| and only computes upto digs digits of result
ashleymills 0:e979170e02e7 3026 * HAC pp. 595, Algorithm 14.12 Modified so you can control how
ashleymills 0:e979170e02e7 3027 * many digits of output are created.
ashleymills 0:e979170e02e7 3028 */
ashleymills 0:e979170e02e7 3029 int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
ashleymills 0:e979170e02e7 3030 {
ashleymills 0:e979170e02e7 3031 mp_int t;
ashleymills 0:e979170e02e7 3032 int res, pa, pb, ix, iy;
ashleymills 0:e979170e02e7 3033 mp_digit u;
ashleymills 0:e979170e02e7 3034 mp_word r;
ashleymills 0:e979170e02e7 3035 mp_digit tmpx, *tmpt, *tmpy;
ashleymills 0:e979170e02e7 3036
ashleymills 0:e979170e02e7 3037 /* can we use the fast multiplier? */
ashleymills 0:e979170e02e7 3038 if (((digs) < MP_WARRAY) &&
ashleymills 0:e979170e02e7 3039 MIN (a->used, b->used) <
ashleymills 0:e979170e02e7 3040 (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
ashleymills 0:e979170e02e7 3041 return fast_s_mp_mul_digs (a, b, c, digs);
ashleymills 0:e979170e02e7 3042 }
ashleymills 0:e979170e02e7 3043
ashleymills 0:e979170e02e7 3044 if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3045 return res;
ashleymills 0:e979170e02e7 3046 }
ashleymills 0:e979170e02e7 3047 t.used = digs;
ashleymills 0:e979170e02e7 3048
ashleymills 0:e979170e02e7 3049 /* compute the digits of the product directly */
ashleymills 0:e979170e02e7 3050 pa = a->used;
ashleymills 0:e979170e02e7 3051 for (ix = 0; ix < pa; ix++) {
ashleymills 0:e979170e02e7 3052 /* set the carry to zero */
ashleymills 0:e979170e02e7 3053 u = 0;
ashleymills 0:e979170e02e7 3054
ashleymills 0:e979170e02e7 3055 /* limit ourselves to making digs digits of output */
ashleymills 0:e979170e02e7 3056 pb = MIN (b->used, digs - ix);
ashleymills 0:e979170e02e7 3057
ashleymills 0:e979170e02e7 3058 /* setup some aliases */
ashleymills 0:e979170e02e7 3059 /* copy of the digit from a used within the nested loop */
ashleymills 0:e979170e02e7 3060 tmpx = a->dp[ix];
ashleymills 0:e979170e02e7 3061
ashleymills 0:e979170e02e7 3062 /* an alias for the destination shifted ix places */
ashleymills 0:e979170e02e7 3063 tmpt = t.dp + ix;
ashleymills 0:e979170e02e7 3064
ashleymills 0:e979170e02e7 3065 /* an alias for the digits of b */
ashleymills 0:e979170e02e7 3066 tmpy = b->dp;
ashleymills 0:e979170e02e7 3067
ashleymills 0:e979170e02e7 3068 /* compute the columns of the output and propagate the carry */
ashleymills 0:e979170e02e7 3069 for (iy = 0; iy < pb; iy++) {
ashleymills 0:e979170e02e7 3070 /* compute the column as a mp_word */
ashleymills 0:e979170e02e7 3071 r = ((mp_word)*tmpt) +
ashleymills 0:e979170e02e7 3072 ((mp_word)tmpx) * ((mp_word)*tmpy++) +
ashleymills 0:e979170e02e7 3073 ((mp_word) u);
ashleymills 0:e979170e02e7 3074
ashleymills 0:e979170e02e7 3075 /* the new column is the lower part of the result */
ashleymills 0:e979170e02e7 3076 *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
ashleymills 0:e979170e02e7 3077
ashleymills 0:e979170e02e7 3078 /* get the carry word from the result */
ashleymills 0:e979170e02e7 3079 u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
ashleymills 0:e979170e02e7 3080 }
ashleymills 0:e979170e02e7 3081 /* set carry if it is placed below digs */
ashleymills 0:e979170e02e7 3082 if (ix + iy < digs) {
ashleymills 0:e979170e02e7 3083 *tmpt = u;
ashleymills 0:e979170e02e7 3084 }
ashleymills 0:e979170e02e7 3085 }
ashleymills 0:e979170e02e7 3086
ashleymills 0:e979170e02e7 3087 mp_clamp (&t);
ashleymills 0:e979170e02e7 3088 mp_exch (&t, c);
ashleymills 0:e979170e02e7 3089
ashleymills 0:e979170e02e7 3090 mp_clear (&t);
ashleymills 0:e979170e02e7 3091 return MP_OKAY;
ashleymills 0:e979170e02e7 3092 }
ashleymills 0:e979170e02e7 3093
ashleymills 0:e979170e02e7 3094
ashleymills 0:e979170e02e7 3095 /*
ashleymills 0:e979170e02e7 3096 * shifts with subtractions when the result is greater than b.
ashleymills 0:e979170e02e7 3097 *
ashleymills 0:e979170e02e7 3098 * The method is slightly modified to shift B unconditionally upto just under
ashleymills 0:e979170e02e7 3099 * the leading bit of b. This saves alot of multiple precision shifting.
ashleymills 0:e979170e02e7 3100 */
ashleymills 0:e979170e02e7 3101 int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
ashleymills 0:e979170e02e7 3102 {
ashleymills 0:e979170e02e7 3103 int x, bits, res;
ashleymills 0:e979170e02e7 3104
ashleymills 0:e979170e02e7 3105 /* how many bits of last digit does b use */
ashleymills 0:e979170e02e7 3106 bits = mp_count_bits (b) % DIGIT_BIT;
ashleymills 0:e979170e02e7 3107
ashleymills 0:e979170e02e7 3108 if (b->used > 1) {
ashleymills 0:e979170e02e7 3109 if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3110 return res;
ashleymills 0:e979170e02e7 3111 }
ashleymills 0:e979170e02e7 3112 } else {
ashleymills 0:e979170e02e7 3113 mp_set(a, 1);
ashleymills 0:e979170e02e7 3114 bits = 1;
ashleymills 0:e979170e02e7 3115 }
ashleymills 0:e979170e02e7 3116
ashleymills 0:e979170e02e7 3117
ashleymills 0:e979170e02e7 3118 /* now compute C = A * B mod b */
ashleymills 0:e979170e02e7 3119 for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
ashleymills 0:e979170e02e7 3120 if ((res = mp_mul_2 (a, a)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3121 return res;
ashleymills 0:e979170e02e7 3122 }
ashleymills 0:e979170e02e7 3123 if (mp_cmp_mag (a, b) != MP_LT) {
ashleymills 0:e979170e02e7 3124 if ((res = s_mp_sub (a, b, a)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3125 return res;
ashleymills 0:e979170e02e7 3126 }
ashleymills 0:e979170e02e7 3127 }
ashleymills 0:e979170e02e7 3128 }
ashleymills 0:e979170e02e7 3129
ashleymills 0:e979170e02e7 3130 return MP_OKAY;
ashleymills 0:e979170e02e7 3131 }
ashleymills 0:e979170e02e7 3132
ashleymills 0:e979170e02e7 3133
ashleymills 0:e979170e02e7 3134 #ifdef MP_LOW_MEM
ashleymills 0:e979170e02e7 3135 #define TAB_SIZE 32
ashleymills 0:e979170e02e7 3136 #else
ashleymills 0:e979170e02e7 3137 #define TAB_SIZE 256
ashleymills 0:e979170e02e7 3138 #endif
ashleymills 0:e979170e02e7 3139
ashleymills 0:e979170e02e7 3140 int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
ashleymills 0:e979170e02e7 3141 {
ashleymills 0:e979170e02e7 3142 mp_int M[TAB_SIZE], res, mu;
ashleymills 0:e979170e02e7 3143 mp_digit buf;
ashleymills 0:e979170e02e7 3144 int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
ashleymills 0:e979170e02e7 3145 int (*redux)(mp_int*,mp_int*,mp_int*);
ashleymills 0:e979170e02e7 3146
ashleymills 0:e979170e02e7 3147 /* find window size */
ashleymills 0:e979170e02e7 3148 x = mp_count_bits (X);
ashleymills 0:e979170e02e7 3149 if (x <= 7) {
ashleymills 0:e979170e02e7 3150 winsize = 2;
ashleymills 0:e979170e02e7 3151 } else if (x <= 36) {
ashleymills 0:e979170e02e7 3152 winsize = 3;
ashleymills 0:e979170e02e7 3153 } else if (x <= 140) {
ashleymills 0:e979170e02e7 3154 winsize = 4;
ashleymills 0:e979170e02e7 3155 } else if (x <= 450) {
ashleymills 0:e979170e02e7 3156 winsize = 5;
ashleymills 0:e979170e02e7 3157 } else if (x <= 1303) {
ashleymills 0:e979170e02e7 3158 winsize = 6;
ashleymills 0:e979170e02e7 3159 } else if (x <= 3529) {
ashleymills 0:e979170e02e7 3160 winsize = 7;
ashleymills 0:e979170e02e7 3161 } else {
ashleymills 0:e979170e02e7 3162 winsize = 8;
ashleymills 0:e979170e02e7 3163 }
ashleymills 0:e979170e02e7 3164
ashleymills 0:e979170e02e7 3165 #ifdef MP_LOW_MEM
ashleymills 0:e979170e02e7 3166 if (winsize > 5) {
ashleymills 0:e979170e02e7 3167 winsize = 5;
ashleymills 0:e979170e02e7 3168 }
ashleymills 0:e979170e02e7 3169 #endif
ashleymills 0:e979170e02e7 3170
ashleymills 0:e979170e02e7 3171 /* init M array */
ashleymills 0:e979170e02e7 3172 /* init first cell */
ashleymills 0:e979170e02e7 3173 if ((err = mp_init(&M[1])) != MP_OKAY) {
ashleymills 0:e979170e02e7 3174 return err;
ashleymills 0:e979170e02e7 3175 }
ashleymills 0:e979170e02e7 3176
ashleymills 0:e979170e02e7 3177 /* now init the second half of the array */
ashleymills 0:e979170e02e7 3178 for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
ashleymills 0:e979170e02e7 3179 if ((err = mp_init(&M[x])) != MP_OKAY) {
ashleymills 0:e979170e02e7 3180 for (y = 1<<(winsize-1); y < x; y++) {
ashleymills 0:e979170e02e7 3181 mp_clear (&M[y]);
ashleymills 0:e979170e02e7 3182 }
ashleymills 0:e979170e02e7 3183 mp_clear(&M[1]);
ashleymills 0:e979170e02e7 3184 return err;
ashleymills 0:e979170e02e7 3185 }
ashleymills 0:e979170e02e7 3186 }
ashleymills 0:e979170e02e7 3187
ashleymills 0:e979170e02e7 3188 /* create mu, used for Barrett reduction */
ashleymills 0:e979170e02e7 3189 if ((err = mp_init (&mu)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3190 goto LBL_M;
ashleymills 0:e979170e02e7 3191 }
ashleymills 0:e979170e02e7 3192
ashleymills 0:e979170e02e7 3193 if (redmode == 0) {
ashleymills 0:e979170e02e7 3194 if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3195 goto LBL_MU;
ashleymills 0:e979170e02e7 3196 }
ashleymills 0:e979170e02e7 3197 redux = mp_reduce;
ashleymills 0:e979170e02e7 3198 } else {
ashleymills 0:e979170e02e7 3199 if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3200 goto LBL_MU;
ashleymills 0:e979170e02e7 3201 }
ashleymills 0:e979170e02e7 3202 redux = mp_reduce_2k_l;
ashleymills 0:e979170e02e7 3203 }
ashleymills 0:e979170e02e7 3204
ashleymills 0:e979170e02e7 3205 /* create M table
ashleymills 0:e979170e02e7 3206 *
ashleymills 0:e979170e02e7 3207 * The M table contains powers of the base,
ashleymills 0:e979170e02e7 3208 * e.g. M[x] = G**x mod P
ashleymills 0:e979170e02e7 3209 *
ashleymills 0:e979170e02e7 3210 * The first half of the table is not
ashleymills 0:e979170e02e7 3211 * computed though accept for M[0] and M[1]
ashleymills 0:e979170e02e7 3212 */
ashleymills 0:e979170e02e7 3213 if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
ashleymills 0:e979170e02e7 3214 goto LBL_MU;
ashleymills 0:e979170e02e7 3215 }
ashleymills 0:e979170e02e7 3216
ashleymills 0:e979170e02e7 3217 /* compute the value at M[1<<(winsize-1)] by squaring
ashleymills 0:e979170e02e7 3218 * M[1] (winsize-1) times
ashleymills 0:e979170e02e7 3219 */
ashleymills 0:e979170e02e7 3220 if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
ashleymills 0:e979170e02e7 3221 goto LBL_MU;
ashleymills 0:e979170e02e7 3222 }
ashleymills 0:e979170e02e7 3223
ashleymills 0:e979170e02e7 3224 for (x = 0; x < (winsize - 1); x++) {
ashleymills 0:e979170e02e7 3225 /* square it */
ashleymills 0:e979170e02e7 3226 if ((err = mp_sqr (&M[1 << (winsize - 1)],
ashleymills 0:e979170e02e7 3227 &M[1 << (winsize - 1)])) != MP_OKAY) {
ashleymills 0:e979170e02e7 3228 goto LBL_MU;
ashleymills 0:e979170e02e7 3229 }
ashleymills 0:e979170e02e7 3230
ashleymills 0:e979170e02e7 3231 /* reduce modulo P */
ashleymills 0:e979170e02e7 3232 if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3233 goto LBL_MU;
ashleymills 0:e979170e02e7 3234 }
ashleymills 0:e979170e02e7 3235 }
ashleymills 0:e979170e02e7 3236
ashleymills 0:e979170e02e7 3237 /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
ashleymills 0:e979170e02e7 3238 * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
ashleymills 0:e979170e02e7 3239 */
ashleymills 0:e979170e02e7 3240 for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
ashleymills 0:e979170e02e7 3241 if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
ashleymills 0:e979170e02e7 3242 goto LBL_MU;
ashleymills 0:e979170e02e7 3243 }
ashleymills 0:e979170e02e7 3244 if ((err = redux (&M[x], P, &mu)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3245 goto LBL_MU;
ashleymills 0:e979170e02e7 3246 }
ashleymills 0:e979170e02e7 3247 }
ashleymills 0:e979170e02e7 3248
ashleymills 0:e979170e02e7 3249 /* setup result */
ashleymills 0:e979170e02e7 3250 if ((err = mp_init (&res)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3251 goto LBL_MU;
ashleymills 0:e979170e02e7 3252 }
ashleymills 0:e979170e02e7 3253 mp_set (&res, 1);
ashleymills 0:e979170e02e7 3254
ashleymills 0:e979170e02e7 3255 /* set initial mode and bit cnt */
ashleymills 0:e979170e02e7 3256 mode = 0;
ashleymills 0:e979170e02e7 3257 bitcnt = 1;
ashleymills 0:e979170e02e7 3258 buf = 0;
ashleymills 0:e979170e02e7 3259 digidx = X->used - 1;
ashleymills 0:e979170e02e7 3260 bitcpy = 0;
ashleymills 0:e979170e02e7 3261 bitbuf = 0;
ashleymills 0:e979170e02e7 3262
ashleymills 0:e979170e02e7 3263 for (;;) {
ashleymills 0:e979170e02e7 3264 /* grab next digit as required */
ashleymills 0:e979170e02e7 3265 if (--bitcnt == 0) {
ashleymills 0:e979170e02e7 3266 /* if digidx == -1 we are out of digits */
ashleymills 0:e979170e02e7 3267 if (digidx == -1) {
ashleymills 0:e979170e02e7 3268 break;
ashleymills 0:e979170e02e7 3269 }
ashleymills 0:e979170e02e7 3270 /* read next digit and reset the bitcnt */
ashleymills 0:e979170e02e7 3271 buf = X->dp[digidx--];
ashleymills 0:e979170e02e7 3272 bitcnt = (int) DIGIT_BIT;
ashleymills 0:e979170e02e7 3273 }
ashleymills 0:e979170e02e7 3274
ashleymills 0:e979170e02e7 3275 /* grab the next msb from the exponent */
ashleymills 0:e979170e02e7 3276 y = (int)(buf >> (mp_digit)(DIGIT_BIT - 1)) & 1;
ashleymills 0:e979170e02e7 3277 buf <<= (mp_digit)1;
ashleymills 0:e979170e02e7 3278
ashleymills 0:e979170e02e7 3279 /* if the bit is zero and mode == 0 then we ignore it
ashleymills 0:e979170e02e7 3280 * These represent the leading zero bits before the first 1 bit
ashleymills 0:e979170e02e7 3281 * in the exponent. Technically this opt is not required but it
ashleymills 0:e979170e02e7 3282 * does lower the # of trivial squaring/reductions used
ashleymills 0:e979170e02e7 3283 */
ashleymills 0:e979170e02e7 3284 if (mode == 0 && y == 0) {
ashleymills 0:e979170e02e7 3285 continue;
ashleymills 0:e979170e02e7 3286 }
ashleymills 0:e979170e02e7 3287
ashleymills 0:e979170e02e7 3288 /* if the bit is zero and mode == 1 then we square */
ashleymills 0:e979170e02e7 3289 if (mode == 1 && y == 0) {
ashleymills 0:e979170e02e7 3290 if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3291 goto LBL_RES;
ashleymills 0:e979170e02e7 3292 }
ashleymills 0:e979170e02e7 3293 if ((err = redux (&res, P, &mu)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3294 goto LBL_RES;
ashleymills 0:e979170e02e7 3295 }
ashleymills 0:e979170e02e7 3296 continue;
ashleymills 0:e979170e02e7 3297 }
ashleymills 0:e979170e02e7 3298
ashleymills 0:e979170e02e7 3299 /* else we add it to the window */
ashleymills 0:e979170e02e7 3300 bitbuf |= (y << (winsize - ++bitcpy));
ashleymills 0:e979170e02e7 3301 mode = 2;
ashleymills 0:e979170e02e7 3302
ashleymills 0:e979170e02e7 3303 if (bitcpy == winsize) {
ashleymills 0:e979170e02e7 3304 /* ok window is filled so square as required and multiply */
ashleymills 0:e979170e02e7 3305 /* square first */
ashleymills 0:e979170e02e7 3306 for (x = 0; x < winsize; x++) {
ashleymills 0:e979170e02e7 3307 if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3308 goto LBL_RES;
ashleymills 0:e979170e02e7 3309 }
ashleymills 0:e979170e02e7 3310 if ((err = redux (&res, P, &mu)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3311 goto LBL_RES;
ashleymills 0:e979170e02e7 3312 }
ashleymills 0:e979170e02e7 3313 }
ashleymills 0:e979170e02e7 3314
ashleymills 0:e979170e02e7 3315 /* then multiply */
ashleymills 0:e979170e02e7 3316 if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3317 goto LBL_RES;
ashleymills 0:e979170e02e7 3318 }
ashleymills 0:e979170e02e7 3319 if ((err = redux (&res, P, &mu)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3320 goto LBL_RES;
ashleymills 0:e979170e02e7 3321 }
ashleymills 0:e979170e02e7 3322
ashleymills 0:e979170e02e7 3323 /* empty window and reset */
ashleymills 0:e979170e02e7 3324 bitcpy = 0;
ashleymills 0:e979170e02e7 3325 bitbuf = 0;
ashleymills 0:e979170e02e7 3326 mode = 1;
ashleymills 0:e979170e02e7 3327 }
ashleymills 0:e979170e02e7 3328 }
ashleymills 0:e979170e02e7 3329
ashleymills 0:e979170e02e7 3330 /* if bits remain then square/multiply */
ashleymills 0:e979170e02e7 3331 if (mode == 2 && bitcpy > 0) {
ashleymills 0:e979170e02e7 3332 /* square then multiply if the bit is set */
ashleymills 0:e979170e02e7 3333 for (x = 0; x < bitcpy; x++) {
ashleymills 0:e979170e02e7 3334 if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3335 goto LBL_RES;
ashleymills 0:e979170e02e7 3336 }
ashleymills 0:e979170e02e7 3337 if ((err = redux (&res, P, &mu)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3338 goto LBL_RES;
ashleymills 0:e979170e02e7 3339 }
ashleymills 0:e979170e02e7 3340
ashleymills 0:e979170e02e7 3341 bitbuf <<= 1;
ashleymills 0:e979170e02e7 3342 if ((bitbuf & (1 << winsize)) != 0) {
ashleymills 0:e979170e02e7 3343 /* then multiply */
ashleymills 0:e979170e02e7 3344 if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3345 goto LBL_RES;
ashleymills 0:e979170e02e7 3346 }
ashleymills 0:e979170e02e7 3347 if ((err = redux (&res, P, &mu)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3348 goto LBL_RES;
ashleymills 0:e979170e02e7 3349 }
ashleymills 0:e979170e02e7 3350 }
ashleymills 0:e979170e02e7 3351 }
ashleymills 0:e979170e02e7 3352 }
ashleymills 0:e979170e02e7 3353
ashleymills 0:e979170e02e7 3354 mp_exch (&res, Y);
ashleymills 0:e979170e02e7 3355 err = MP_OKAY;
ashleymills 0:e979170e02e7 3356 LBL_RES:mp_clear (&res);
ashleymills 0:e979170e02e7 3357 LBL_MU:mp_clear (&mu);
ashleymills 0:e979170e02e7 3358 LBL_M:
ashleymills 0:e979170e02e7 3359 mp_clear(&M[1]);
ashleymills 0:e979170e02e7 3360 for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
ashleymills 0:e979170e02e7 3361 mp_clear (&M[x]);
ashleymills 0:e979170e02e7 3362 }
ashleymills 0:e979170e02e7 3363 return err;
ashleymills 0:e979170e02e7 3364 }
ashleymills 0:e979170e02e7 3365
ashleymills 0:e979170e02e7 3366
ashleymills 0:e979170e02e7 3367 /* pre-calculate the value required for Barrett reduction
ashleymills 0:e979170e02e7 3368 * For a given modulus "b" it calulates the value required in "a"
ashleymills 0:e979170e02e7 3369 */
ashleymills 0:e979170e02e7 3370 int mp_reduce_setup (mp_int * a, mp_int * b)
ashleymills 0:e979170e02e7 3371 {
ashleymills 0:e979170e02e7 3372 int res;
ashleymills 0:e979170e02e7 3373
ashleymills 0:e979170e02e7 3374 if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3375 return res;
ashleymills 0:e979170e02e7 3376 }
ashleymills 0:e979170e02e7 3377 return mp_div (a, b, a, NULL);
ashleymills 0:e979170e02e7 3378 }
ashleymills 0:e979170e02e7 3379
ashleymills 0:e979170e02e7 3380
ashleymills 0:e979170e02e7 3381 /* reduces x mod m, assumes 0 < x < m**2, mu is
ashleymills 0:e979170e02e7 3382 * precomputed via mp_reduce_setup.
ashleymills 0:e979170e02e7 3383 * From HAC pp.604 Algorithm 14.42
ashleymills 0:e979170e02e7 3384 */
ashleymills 0:e979170e02e7 3385 int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
ashleymills 0:e979170e02e7 3386 {
ashleymills 0:e979170e02e7 3387 mp_int q;
ashleymills 0:e979170e02e7 3388 int res, um = m->used;
ashleymills 0:e979170e02e7 3389
ashleymills 0:e979170e02e7 3390 /* q = x */
ashleymills 0:e979170e02e7 3391 if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3392 return res;
ashleymills 0:e979170e02e7 3393 }
ashleymills 0:e979170e02e7 3394
ashleymills 0:e979170e02e7 3395 /* q1 = x / b**(k-1) */
ashleymills 0:e979170e02e7 3396 mp_rshd (&q, um - 1);
ashleymills 0:e979170e02e7 3397
ashleymills 0:e979170e02e7 3398 /* according to HAC this optimization is ok */
ashleymills 0:e979170e02e7 3399 if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
ashleymills 0:e979170e02e7 3400 if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3401 goto CLEANUP;
ashleymills 0:e979170e02e7 3402 }
ashleymills 0:e979170e02e7 3403 } else {
ashleymills 0:e979170e02e7 3404 #ifdef BN_S_MP_MUL_HIGH_DIGS_C
ashleymills 0:e979170e02e7 3405 if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3406 goto CLEANUP;
ashleymills 0:e979170e02e7 3407 }
ashleymills 0:e979170e02e7 3408 #elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
ashleymills 0:e979170e02e7 3409 if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3410 goto CLEANUP;
ashleymills 0:e979170e02e7 3411 }
ashleymills 0:e979170e02e7 3412 #else
ashleymills 0:e979170e02e7 3413 {
ashleymills 0:e979170e02e7 3414 res = MP_VAL;
ashleymills 0:e979170e02e7 3415 goto CLEANUP;
ashleymills 0:e979170e02e7 3416 }
ashleymills 0:e979170e02e7 3417 #endif
ashleymills 0:e979170e02e7 3418 }
ashleymills 0:e979170e02e7 3419
ashleymills 0:e979170e02e7 3420 /* q3 = q2 / b**(k+1) */
ashleymills 0:e979170e02e7 3421 mp_rshd (&q, um + 1);
ashleymills 0:e979170e02e7 3422
ashleymills 0:e979170e02e7 3423 /* x = x mod b**(k+1), quick (no division) */
ashleymills 0:e979170e02e7 3424 if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3425 goto CLEANUP;
ashleymills 0:e979170e02e7 3426 }
ashleymills 0:e979170e02e7 3427
ashleymills 0:e979170e02e7 3428 /* q = q * m mod b**(k+1), quick (no division) */
ashleymills 0:e979170e02e7 3429 if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3430 goto CLEANUP;
ashleymills 0:e979170e02e7 3431 }
ashleymills 0:e979170e02e7 3432
ashleymills 0:e979170e02e7 3433 /* x = x - q */
ashleymills 0:e979170e02e7 3434 if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3435 goto CLEANUP;
ashleymills 0:e979170e02e7 3436 }
ashleymills 0:e979170e02e7 3437
ashleymills 0:e979170e02e7 3438 /* If x < 0, add b**(k+1) to it */
ashleymills 0:e979170e02e7 3439 if (mp_cmp_d (x, 0) == MP_LT) {
ashleymills 0:e979170e02e7 3440 mp_set (&q, 1);
ashleymills 0:e979170e02e7 3441 if ((res = mp_lshd (&q, um + 1)) != MP_OKAY)
ashleymills 0:e979170e02e7 3442 goto CLEANUP;
ashleymills 0:e979170e02e7 3443 if ((res = mp_add (x, &q, x)) != MP_OKAY)
ashleymills 0:e979170e02e7 3444 goto CLEANUP;
ashleymills 0:e979170e02e7 3445 }
ashleymills 0:e979170e02e7 3446
ashleymills 0:e979170e02e7 3447 /* Back off if it's too big */
ashleymills 0:e979170e02e7 3448 while (mp_cmp (x, m) != MP_LT) {
ashleymills 0:e979170e02e7 3449 if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3450 goto CLEANUP;
ashleymills 0:e979170e02e7 3451 }
ashleymills 0:e979170e02e7 3452 }
ashleymills 0:e979170e02e7 3453
ashleymills 0:e979170e02e7 3454 CLEANUP:
ashleymills 0:e979170e02e7 3455 mp_clear (&q);
ashleymills 0:e979170e02e7 3456
ashleymills 0:e979170e02e7 3457 return res;
ashleymills 0:e979170e02e7 3458 }
ashleymills 0:e979170e02e7 3459
ashleymills 0:e979170e02e7 3460
ashleymills 0:e979170e02e7 3461 /* reduces a modulo n where n is of the form 2**p - d
ashleymills 0:e979170e02e7 3462 This differs from reduce_2k since "d" can be larger
ashleymills 0:e979170e02e7 3463 than a single digit.
ashleymills 0:e979170e02e7 3464 */
ashleymills 0:e979170e02e7 3465 int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
ashleymills 0:e979170e02e7 3466 {
ashleymills 0:e979170e02e7 3467 mp_int q;
ashleymills 0:e979170e02e7 3468 int p, res;
ashleymills 0:e979170e02e7 3469
ashleymills 0:e979170e02e7 3470 if ((res = mp_init(&q)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3471 return res;
ashleymills 0:e979170e02e7 3472 }
ashleymills 0:e979170e02e7 3473
ashleymills 0:e979170e02e7 3474 p = mp_count_bits(n);
ashleymills 0:e979170e02e7 3475 top:
ashleymills 0:e979170e02e7 3476 /* q = a/2**p, a = a mod 2**p */
ashleymills 0:e979170e02e7 3477 if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3478 goto ERR;
ashleymills 0:e979170e02e7 3479 }
ashleymills 0:e979170e02e7 3480
ashleymills 0:e979170e02e7 3481 /* q = q * d */
ashleymills 0:e979170e02e7 3482 if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3483 goto ERR;
ashleymills 0:e979170e02e7 3484 }
ashleymills 0:e979170e02e7 3485
ashleymills 0:e979170e02e7 3486 /* a = a + q */
ashleymills 0:e979170e02e7 3487 if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3488 goto ERR;
ashleymills 0:e979170e02e7 3489 }
ashleymills 0:e979170e02e7 3490
ashleymills 0:e979170e02e7 3491 if (mp_cmp_mag(a, n) != MP_LT) {
ashleymills 0:e979170e02e7 3492 s_mp_sub(a, n, a);
ashleymills 0:e979170e02e7 3493 goto top;
ashleymills 0:e979170e02e7 3494 }
ashleymills 0:e979170e02e7 3495
ashleymills 0:e979170e02e7 3496 ERR:
ashleymills 0:e979170e02e7 3497 mp_clear(&q);
ashleymills 0:e979170e02e7 3498 return res;
ashleymills 0:e979170e02e7 3499 }
ashleymills 0:e979170e02e7 3500
ashleymills 0:e979170e02e7 3501
ashleymills 0:e979170e02e7 3502 /* determines the setup value */
ashleymills 0:e979170e02e7 3503 int mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
ashleymills 0:e979170e02e7 3504 {
ashleymills 0:e979170e02e7 3505 int res;
ashleymills 0:e979170e02e7 3506 mp_int tmp;
ashleymills 0:e979170e02e7 3507
ashleymills 0:e979170e02e7 3508 if ((res = mp_init(&tmp)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3509 return res;
ashleymills 0:e979170e02e7 3510 }
ashleymills 0:e979170e02e7 3511
ashleymills 0:e979170e02e7 3512 if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
ashleymills 0:e979170e02e7 3513 goto ERR;
ashleymills 0:e979170e02e7 3514 }
ashleymills 0:e979170e02e7 3515
ashleymills 0:e979170e02e7 3516 if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3517 goto ERR;
ashleymills 0:e979170e02e7 3518 }
ashleymills 0:e979170e02e7 3519
ashleymills 0:e979170e02e7 3520 ERR:
ashleymills 0:e979170e02e7 3521 mp_clear(&tmp);
ashleymills 0:e979170e02e7 3522 return res;
ashleymills 0:e979170e02e7 3523 }
ashleymills 0:e979170e02e7 3524
ashleymills 0:e979170e02e7 3525
ashleymills 0:e979170e02e7 3526 /* multiplies |a| * |b| and does not compute the lower digs digits
ashleymills 0:e979170e02e7 3527 * [meant to get the higher part of the product]
ashleymills 0:e979170e02e7 3528 */
ashleymills 0:e979170e02e7 3529 int
ashleymills 0:e979170e02e7 3530 s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
ashleymills 0:e979170e02e7 3531 {
ashleymills 0:e979170e02e7 3532 mp_int t;
ashleymills 0:e979170e02e7 3533 int res, pa, pb, ix, iy;
ashleymills 0:e979170e02e7 3534 mp_digit u;
ashleymills 0:e979170e02e7 3535 mp_word r;
ashleymills 0:e979170e02e7 3536 mp_digit tmpx, *tmpt, *tmpy;
ashleymills 0:e979170e02e7 3537
ashleymills 0:e979170e02e7 3538 /* can we use the fast multiplier? */
ashleymills 0:e979170e02e7 3539 #ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
ashleymills 0:e979170e02e7 3540 if (((a->used + b->used + 1) < MP_WARRAY)
ashleymills 0:e979170e02e7 3541 && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
ashleymills 0:e979170e02e7 3542 return fast_s_mp_mul_high_digs (a, b, c, digs);
ashleymills 0:e979170e02e7 3543 }
ashleymills 0:e979170e02e7 3544 #endif
ashleymills 0:e979170e02e7 3545
ashleymills 0:e979170e02e7 3546 if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3547 return res;
ashleymills 0:e979170e02e7 3548 }
ashleymills 0:e979170e02e7 3549 t.used = a->used + b->used + 1;
ashleymills 0:e979170e02e7 3550
ashleymills 0:e979170e02e7 3551 pa = a->used;
ashleymills 0:e979170e02e7 3552 pb = b->used;
ashleymills 0:e979170e02e7 3553 for (ix = 0; ix < pa; ix++) {
ashleymills 0:e979170e02e7 3554 /* clear the carry */
ashleymills 0:e979170e02e7 3555 u = 0;
ashleymills 0:e979170e02e7 3556
ashleymills 0:e979170e02e7 3557 /* left hand side of A[ix] * B[iy] */
ashleymills 0:e979170e02e7 3558 tmpx = a->dp[ix];
ashleymills 0:e979170e02e7 3559
ashleymills 0:e979170e02e7 3560 /* alias to the address of where the digits will be stored */
ashleymills 0:e979170e02e7 3561 tmpt = &(t.dp[digs]);
ashleymills 0:e979170e02e7 3562
ashleymills 0:e979170e02e7 3563 /* alias for where to read the right hand side from */
ashleymills 0:e979170e02e7 3564 tmpy = b->dp + (digs - ix);
ashleymills 0:e979170e02e7 3565
ashleymills 0:e979170e02e7 3566 for (iy = digs - ix; iy < pb; iy++) {
ashleymills 0:e979170e02e7 3567 /* calculate the double precision result */
ashleymills 0:e979170e02e7 3568 r = ((mp_word)*tmpt) +
ashleymills 0:e979170e02e7 3569 ((mp_word)tmpx) * ((mp_word)*tmpy++) +
ashleymills 0:e979170e02e7 3570 ((mp_word) u);
ashleymills 0:e979170e02e7 3571
ashleymills 0:e979170e02e7 3572 /* get the lower part */
ashleymills 0:e979170e02e7 3573 *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
ashleymills 0:e979170e02e7 3574
ashleymills 0:e979170e02e7 3575 /* carry the carry */
ashleymills 0:e979170e02e7 3576 u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
ashleymills 0:e979170e02e7 3577 }
ashleymills 0:e979170e02e7 3578 *tmpt = u;
ashleymills 0:e979170e02e7 3579 }
ashleymills 0:e979170e02e7 3580 mp_clamp (&t);
ashleymills 0:e979170e02e7 3581 mp_exch (&t, c);
ashleymills 0:e979170e02e7 3582 mp_clear (&t);
ashleymills 0:e979170e02e7 3583 return MP_OKAY;
ashleymills 0:e979170e02e7 3584 }
ashleymills 0:e979170e02e7 3585
ashleymills 0:e979170e02e7 3586
ashleymills 0:e979170e02e7 3587 /* this is a modified version of fast_s_mul_digs that only produces
ashleymills 0:e979170e02e7 3588 * output digits *above* digs. See the comments for fast_s_mul_digs
ashleymills 0:e979170e02e7 3589 * to see how it works.
ashleymills 0:e979170e02e7 3590 *
ashleymills 0:e979170e02e7 3591 * This is used in the Barrett reduction since for one of the multiplications
ashleymills 0:e979170e02e7 3592 * only the higher digits were needed. This essentially halves the work.
ashleymills 0:e979170e02e7 3593 *
ashleymills 0:e979170e02e7 3594 * Based on Algorithm 14.12 on pp.595 of HAC.
ashleymills 0:e979170e02e7 3595 */
ashleymills 0:e979170e02e7 3596 int fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
ashleymills 0:e979170e02e7 3597 {
ashleymills 0:e979170e02e7 3598 int olduse, res, pa, ix, iz;
ashleymills 0:e979170e02e7 3599 #ifdef CYASSL_SMALL_STACK
ashleymills 0:e979170e02e7 3600 mp_digit* W; /* uses dynamic memory and slower */
ashleymills 0:e979170e02e7 3601 #else
ashleymills 0:e979170e02e7 3602 mp_digit W[MP_WARRAY];
ashleymills 0:e979170e02e7 3603 #endif
ashleymills 0:e979170e02e7 3604 mp_word _W;
ashleymills 0:e979170e02e7 3605
ashleymills 0:e979170e02e7 3606 /* grow the destination as required */
ashleymills 0:e979170e02e7 3607 pa = a->used + b->used;
ashleymills 0:e979170e02e7 3608 if (c->alloc < pa) {
ashleymills 0:e979170e02e7 3609 if ((res = mp_grow (c, pa)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3610 return res;
ashleymills 0:e979170e02e7 3611 }
ashleymills 0:e979170e02e7 3612 }
ashleymills 0:e979170e02e7 3613
ashleymills 0:e979170e02e7 3614 if (pa > MP_WARRAY)
ashleymills 0:e979170e02e7 3615 return MP_RANGE; /* TAO range check */
ashleymills 0:e979170e02e7 3616
ashleymills 0:e979170e02e7 3617 #ifdef CYASSL_SMALL_STACK
ashleymills 0:e979170e02e7 3618 W = (mp_digit*)XMALLOC(sizeof(mp_digit) * MP_WARRAY, 0, DYNAMIC_TYPE_BIGINT);
ashleymills 0:e979170e02e7 3619 if (W == NULL)
ashleymills 0:e979170e02e7 3620 return MP_MEM;
ashleymills 0:e979170e02e7 3621 #endif
ashleymills 0:e979170e02e7 3622
ashleymills 0:e979170e02e7 3623 /* number of output digits to produce */
ashleymills 0:e979170e02e7 3624 pa = a->used + b->used;
ashleymills 0:e979170e02e7 3625 _W = 0;
ashleymills 0:e979170e02e7 3626 for (ix = digs; ix < pa; ix++) {
ashleymills 0:e979170e02e7 3627 int tx, ty, iy;
ashleymills 0:e979170e02e7 3628 mp_digit *tmpx, *tmpy;
ashleymills 0:e979170e02e7 3629
ashleymills 0:e979170e02e7 3630 /* get offsets into the two bignums */
ashleymills 0:e979170e02e7 3631 ty = MIN(b->used-1, ix);
ashleymills 0:e979170e02e7 3632 tx = ix - ty;
ashleymills 0:e979170e02e7 3633
ashleymills 0:e979170e02e7 3634 /* setup temp aliases */
ashleymills 0:e979170e02e7 3635 tmpx = a->dp + tx;
ashleymills 0:e979170e02e7 3636 tmpy = b->dp + ty;
ashleymills 0:e979170e02e7 3637
ashleymills 0:e979170e02e7 3638 /* this is the number of times the loop will iterrate, essentially its
ashleymills 0:e979170e02e7 3639 while (tx++ < a->used && ty-- >= 0) { ... }
ashleymills 0:e979170e02e7 3640 */
ashleymills 0:e979170e02e7 3641 iy = MIN(a->used-tx, ty+1);
ashleymills 0:e979170e02e7 3642
ashleymills 0:e979170e02e7 3643 /* execute loop */
ashleymills 0:e979170e02e7 3644 for (iz = 0; iz < iy; iz++) {
ashleymills 0:e979170e02e7 3645 _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
ashleymills 0:e979170e02e7 3646 }
ashleymills 0:e979170e02e7 3647
ashleymills 0:e979170e02e7 3648 /* store term */
ashleymills 0:e979170e02e7 3649 W[ix] = ((mp_digit)_W) & MP_MASK;
ashleymills 0:e979170e02e7 3650
ashleymills 0:e979170e02e7 3651 /* make next carry */
ashleymills 0:e979170e02e7 3652 _W = _W >> ((mp_word)DIGIT_BIT);
ashleymills 0:e979170e02e7 3653 }
ashleymills 0:e979170e02e7 3654
ashleymills 0:e979170e02e7 3655 /* setup dest */
ashleymills 0:e979170e02e7 3656 olduse = c->used;
ashleymills 0:e979170e02e7 3657 c->used = pa;
ashleymills 0:e979170e02e7 3658
ashleymills 0:e979170e02e7 3659 {
ashleymills 0:e979170e02e7 3660 register mp_digit *tmpc;
ashleymills 0:e979170e02e7 3661
ashleymills 0:e979170e02e7 3662 tmpc = c->dp + digs;
ashleymills 0:e979170e02e7 3663 for (ix = digs; ix <= pa; ix++) {
ashleymills 0:e979170e02e7 3664 /* now extract the previous digit [below the carry] */
ashleymills 0:e979170e02e7 3665 *tmpc++ = W[ix];
ashleymills 0:e979170e02e7 3666 }
ashleymills 0:e979170e02e7 3667
ashleymills 0:e979170e02e7 3668 /* clear unused digits [that existed in the old copy of c] */
ashleymills 0:e979170e02e7 3669 for (; ix < olduse; ix++) {
ashleymills 0:e979170e02e7 3670 *tmpc++ = 0;
ashleymills 0:e979170e02e7 3671 }
ashleymills 0:e979170e02e7 3672 }
ashleymills 0:e979170e02e7 3673 mp_clamp (c);
ashleymills 0:e979170e02e7 3674
ashleymills 0:e979170e02e7 3675 #ifdef CYASSL_SMALL_STACK
ashleymills 0:e979170e02e7 3676 XFREE(W, 0, DYNAMIC_TYPE_BIGINT);
ashleymills 0:e979170e02e7 3677 #endif
ashleymills 0:e979170e02e7 3678
ashleymills 0:e979170e02e7 3679 return MP_OKAY;
ashleymills 0:e979170e02e7 3680 }
ashleymills 0:e979170e02e7 3681
ashleymills 0:e979170e02e7 3682
ashleymills 0:e979170e02e7 3683 /* set a 32-bit const */
ashleymills 0:e979170e02e7 3684 int mp_set_int (mp_int * a, unsigned long b)
ashleymills 0:e979170e02e7 3685 {
ashleymills 0:e979170e02e7 3686 int x, res;
ashleymills 0:e979170e02e7 3687
ashleymills 0:e979170e02e7 3688 mp_zero (a);
ashleymills 0:e979170e02e7 3689
ashleymills 0:e979170e02e7 3690 /* set four bits at a time */
ashleymills 0:e979170e02e7 3691 for (x = 0; x < 8; x++) {
ashleymills 0:e979170e02e7 3692 /* shift the number up four bits */
ashleymills 0:e979170e02e7 3693 if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3694 return res;
ashleymills 0:e979170e02e7 3695 }
ashleymills 0:e979170e02e7 3696
ashleymills 0:e979170e02e7 3697 /* OR in the top four bits of the source */
ashleymills 0:e979170e02e7 3698 a->dp[0] |= (b >> 28) & 15;
ashleymills 0:e979170e02e7 3699
ashleymills 0:e979170e02e7 3700 /* shift the source up to the next four bits */
ashleymills 0:e979170e02e7 3701 b <<= 4;
ashleymills 0:e979170e02e7 3702
ashleymills 0:e979170e02e7 3703 /* ensure that digits are not clamped off */
ashleymills 0:e979170e02e7 3704 a->used += 1;
ashleymills 0:e979170e02e7 3705 }
ashleymills 0:e979170e02e7 3706 mp_clamp (a);
ashleymills 0:e979170e02e7 3707 return MP_OKAY;
ashleymills 0:e979170e02e7 3708 }
ashleymills 0:e979170e02e7 3709
ashleymills 0:e979170e02e7 3710
ashleymills 0:e979170e02e7 3711 #if defined(CYASSL_KEY_GEN) || defined(HAVE_ECC)
ashleymills 0:e979170e02e7 3712
ashleymills 0:e979170e02e7 3713 /* c = a * a (mod b) */
ashleymills 0:e979170e02e7 3714 int mp_sqrmod (mp_int * a, mp_int * b, mp_int * c)
ashleymills 0:e979170e02e7 3715 {
ashleymills 0:e979170e02e7 3716 int res;
ashleymills 0:e979170e02e7 3717 mp_int t;
ashleymills 0:e979170e02e7 3718
ashleymills 0:e979170e02e7 3719 if ((res = mp_init (&t)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3720 return res;
ashleymills 0:e979170e02e7 3721 }
ashleymills 0:e979170e02e7 3722
ashleymills 0:e979170e02e7 3723 if ((res = mp_sqr (a, &t)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3724 mp_clear (&t);
ashleymills 0:e979170e02e7 3725 return res;
ashleymills 0:e979170e02e7 3726 }
ashleymills 0:e979170e02e7 3727 res = mp_mod (&t, b, c);
ashleymills 0:e979170e02e7 3728 mp_clear (&t);
ashleymills 0:e979170e02e7 3729 return res;
ashleymills 0:e979170e02e7 3730 }
ashleymills 0:e979170e02e7 3731
ashleymills 0:e979170e02e7 3732 #endif
ashleymills 0:e979170e02e7 3733
ashleymills 0:e979170e02e7 3734
ashleymills 0:e979170e02e7 3735 #if defined(CYASSL_KEY_GEN) || defined(HAVE_ECC) || !defined(NO_PWDBASED)
ashleymills 0:e979170e02e7 3736
ashleymills 0:e979170e02e7 3737 /* single digit addition */
ashleymills 0:e979170e02e7 3738 int mp_add_d (mp_int* a, mp_digit b, mp_int* c)
ashleymills 0:e979170e02e7 3739 {
ashleymills 0:e979170e02e7 3740 int res, ix, oldused;
ashleymills 0:e979170e02e7 3741 mp_digit *tmpa, *tmpc, mu;
ashleymills 0:e979170e02e7 3742
ashleymills 0:e979170e02e7 3743 /* grow c as required */
ashleymills 0:e979170e02e7 3744 if (c->alloc < a->used + 1) {
ashleymills 0:e979170e02e7 3745 if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3746 return res;
ashleymills 0:e979170e02e7 3747 }
ashleymills 0:e979170e02e7 3748 }
ashleymills 0:e979170e02e7 3749
ashleymills 0:e979170e02e7 3750 /* if a is negative and |a| >= b, call c = |a| - b */
ashleymills 0:e979170e02e7 3751 if (a->sign == MP_NEG && (a->used > 1 || a->dp[0] >= b)) {
ashleymills 0:e979170e02e7 3752 /* temporarily fix sign of a */
ashleymills 0:e979170e02e7 3753 a->sign = MP_ZPOS;
ashleymills 0:e979170e02e7 3754
ashleymills 0:e979170e02e7 3755 /* c = |a| - b */
ashleymills 0:e979170e02e7 3756 res = mp_sub_d(a, b, c);
ashleymills 0:e979170e02e7 3757
ashleymills 0:e979170e02e7 3758 /* fix sign */
ashleymills 0:e979170e02e7 3759 a->sign = c->sign = MP_NEG;
ashleymills 0:e979170e02e7 3760
ashleymills 0:e979170e02e7 3761 /* clamp */
ashleymills 0:e979170e02e7 3762 mp_clamp(c);
ashleymills 0:e979170e02e7 3763
ashleymills 0:e979170e02e7 3764 return res;
ashleymills 0:e979170e02e7 3765 }
ashleymills 0:e979170e02e7 3766
ashleymills 0:e979170e02e7 3767 /* old number of used digits in c */
ashleymills 0:e979170e02e7 3768 oldused = c->used;
ashleymills 0:e979170e02e7 3769
ashleymills 0:e979170e02e7 3770 /* sign always positive */
ashleymills 0:e979170e02e7 3771 c->sign = MP_ZPOS;
ashleymills 0:e979170e02e7 3772
ashleymills 0:e979170e02e7 3773 /* source alias */
ashleymills 0:e979170e02e7 3774 tmpa = a->dp;
ashleymills 0:e979170e02e7 3775
ashleymills 0:e979170e02e7 3776 /* destination alias */
ashleymills 0:e979170e02e7 3777 tmpc = c->dp;
ashleymills 0:e979170e02e7 3778
ashleymills 0:e979170e02e7 3779 /* if a is positive */
ashleymills 0:e979170e02e7 3780 if (a->sign == MP_ZPOS) {
ashleymills 0:e979170e02e7 3781 /* add digit, after this we're propagating
ashleymills 0:e979170e02e7 3782 * the carry.
ashleymills 0:e979170e02e7 3783 */
ashleymills 0:e979170e02e7 3784 *tmpc = *tmpa++ + b;
ashleymills 0:e979170e02e7 3785 mu = *tmpc >> DIGIT_BIT;
ashleymills 0:e979170e02e7 3786 *tmpc++ &= MP_MASK;
ashleymills 0:e979170e02e7 3787
ashleymills 0:e979170e02e7 3788 /* now handle rest of the digits */
ashleymills 0:e979170e02e7 3789 for (ix = 1; ix < a->used; ix++) {
ashleymills 0:e979170e02e7 3790 *tmpc = *tmpa++ + mu;
ashleymills 0:e979170e02e7 3791 mu = *tmpc >> DIGIT_BIT;
ashleymills 0:e979170e02e7 3792 *tmpc++ &= MP_MASK;
ashleymills 0:e979170e02e7 3793 }
ashleymills 0:e979170e02e7 3794 /* set final carry */
ashleymills 0:e979170e02e7 3795 if (mu != 0 && ix < c->alloc) {
ashleymills 0:e979170e02e7 3796 ix++;
ashleymills 0:e979170e02e7 3797 *tmpc++ = mu;
ashleymills 0:e979170e02e7 3798 }
ashleymills 0:e979170e02e7 3799
ashleymills 0:e979170e02e7 3800 /* setup size */
ashleymills 0:e979170e02e7 3801 c->used = a->used + 1;
ashleymills 0:e979170e02e7 3802 } else {
ashleymills 0:e979170e02e7 3803 /* a was negative and |a| < b */
ashleymills 0:e979170e02e7 3804 c->used = 1;
ashleymills 0:e979170e02e7 3805
ashleymills 0:e979170e02e7 3806 /* the result is a single digit */
ashleymills 0:e979170e02e7 3807 if (a->used == 1) {
ashleymills 0:e979170e02e7 3808 *tmpc++ = b - a->dp[0];
ashleymills 0:e979170e02e7 3809 } else {
ashleymills 0:e979170e02e7 3810 *tmpc++ = b;
ashleymills 0:e979170e02e7 3811 }
ashleymills 0:e979170e02e7 3812
ashleymills 0:e979170e02e7 3813 /* setup count so the clearing of oldused
ashleymills 0:e979170e02e7 3814 * can fall through correctly
ashleymills 0:e979170e02e7 3815 */
ashleymills 0:e979170e02e7 3816 ix = 1;
ashleymills 0:e979170e02e7 3817 }
ashleymills 0:e979170e02e7 3818
ashleymills 0:e979170e02e7 3819 /* now zero to oldused */
ashleymills 0:e979170e02e7 3820 while (ix++ < oldused) {
ashleymills 0:e979170e02e7 3821 *tmpc++ = 0;
ashleymills 0:e979170e02e7 3822 }
ashleymills 0:e979170e02e7 3823 mp_clamp(c);
ashleymills 0:e979170e02e7 3824
ashleymills 0:e979170e02e7 3825 return MP_OKAY;
ashleymills 0:e979170e02e7 3826 }
ashleymills 0:e979170e02e7 3827
ashleymills 0:e979170e02e7 3828
ashleymills 0:e979170e02e7 3829 /* single digit subtraction */
ashleymills 0:e979170e02e7 3830 int mp_sub_d (mp_int * a, mp_digit b, mp_int * c)
ashleymills 0:e979170e02e7 3831 {
ashleymills 0:e979170e02e7 3832 mp_digit *tmpa, *tmpc, mu;
ashleymills 0:e979170e02e7 3833 int res, ix, oldused;
ashleymills 0:e979170e02e7 3834
ashleymills 0:e979170e02e7 3835 /* grow c as required */
ashleymills 0:e979170e02e7 3836 if (c->alloc < a->used + 1) {
ashleymills 0:e979170e02e7 3837 if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3838 return res;
ashleymills 0:e979170e02e7 3839 }
ashleymills 0:e979170e02e7 3840 }
ashleymills 0:e979170e02e7 3841
ashleymills 0:e979170e02e7 3842 /* if a is negative just do an unsigned
ashleymills 0:e979170e02e7 3843 * addition [with fudged signs]
ashleymills 0:e979170e02e7 3844 */
ashleymills 0:e979170e02e7 3845 if (a->sign == MP_NEG) {
ashleymills 0:e979170e02e7 3846 a->sign = MP_ZPOS;
ashleymills 0:e979170e02e7 3847 res = mp_add_d(a, b, c);
ashleymills 0:e979170e02e7 3848 a->sign = c->sign = MP_NEG;
ashleymills 0:e979170e02e7 3849
ashleymills 0:e979170e02e7 3850 /* clamp */
ashleymills 0:e979170e02e7 3851 mp_clamp(c);
ashleymills 0:e979170e02e7 3852
ashleymills 0:e979170e02e7 3853 return res;
ashleymills 0:e979170e02e7 3854 }
ashleymills 0:e979170e02e7 3855
ashleymills 0:e979170e02e7 3856 /* setup regs */
ashleymills 0:e979170e02e7 3857 oldused = c->used;
ashleymills 0:e979170e02e7 3858 tmpa = a->dp;
ashleymills 0:e979170e02e7 3859 tmpc = c->dp;
ashleymills 0:e979170e02e7 3860
ashleymills 0:e979170e02e7 3861 /* if a <= b simply fix the single digit */
ashleymills 0:e979170e02e7 3862 if ((a->used == 1 && a->dp[0] <= b) || a->used == 0) {
ashleymills 0:e979170e02e7 3863 if (a->used == 1) {
ashleymills 0:e979170e02e7 3864 *tmpc++ = b - *tmpa;
ashleymills 0:e979170e02e7 3865 } else {
ashleymills 0:e979170e02e7 3866 *tmpc++ = b;
ashleymills 0:e979170e02e7 3867 }
ashleymills 0:e979170e02e7 3868 ix = 1;
ashleymills 0:e979170e02e7 3869
ashleymills 0:e979170e02e7 3870 /* negative/1digit */
ashleymills 0:e979170e02e7 3871 c->sign = MP_NEG;
ashleymills 0:e979170e02e7 3872 c->used = 1;
ashleymills 0:e979170e02e7 3873 } else {
ashleymills 0:e979170e02e7 3874 /* positive/size */
ashleymills 0:e979170e02e7 3875 c->sign = MP_ZPOS;
ashleymills 0:e979170e02e7 3876 c->used = a->used;
ashleymills 0:e979170e02e7 3877
ashleymills 0:e979170e02e7 3878 /* subtract first digit */
ashleymills 0:e979170e02e7 3879 *tmpc = *tmpa++ - b;
ashleymills 0:e979170e02e7 3880 mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1);
ashleymills 0:e979170e02e7 3881 *tmpc++ &= MP_MASK;
ashleymills 0:e979170e02e7 3882
ashleymills 0:e979170e02e7 3883 /* handle rest of the digits */
ashleymills 0:e979170e02e7 3884 for (ix = 1; ix < a->used; ix++) {
ashleymills 0:e979170e02e7 3885 *tmpc = *tmpa++ - mu;
ashleymills 0:e979170e02e7 3886 mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1);
ashleymills 0:e979170e02e7 3887 *tmpc++ &= MP_MASK;
ashleymills 0:e979170e02e7 3888 }
ashleymills 0:e979170e02e7 3889 }
ashleymills 0:e979170e02e7 3890
ashleymills 0:e979170e02e7 3891 /* zero excess digits */
ashleymills 0:e979170e02e7 3892 while (ix++ < oldused) {
ashleymills 0:e979170e02e7 3893 *tmpc++ = 0;
ashleymills 0:e979170e02e7 3894 }
ashleymills 0:e979170e02e7 3895 mp_clamp(c);
ashleymills 0:e979170e02e7 3896 return MP_OKAY;
ashleymills 0:e979170e02e7 3897 }
ashleymills 0:e979170e02e7 3898
ashleymills 0:e979170e02e7 3899 #endif /* CYASSL_KEY_GEN || HAVE_ECC */
ashleymills 0:e979170e02e7 3900
ashleymills 0:e979170e02e7 3901
ashleymills 0:e979170e02e7 3902 #ifdef CYASSL_KEY_GEN
ashleymills 0:e979170e02e7 3903
ashleymills 0:e979170e02e7 3904 int mp_cnt_lsb(mp_int *a);
ashleymills 0:e979170e02e7 3905
ashleymills 0:e979170e02e7 3906 static int s_is_power_of_two(mp_digit b, int *p)
ashleymills 0:e979170e02e7 3907 {
ashleymills 0:e979170e02e7 3908 int x;
ashleymills 0:e979170e02e7 3909
ashleymills 0:e979170e02e7 3910 /* fast return if no power of two */
ashleymills 0:e979170e02e7 3911 if ((b==0) || (b & (b-1))) {
ashleymills 0:e979170e02e7 3912 return 0;
ashleymills 0:e979170e02e7 3913 }
ashleymills 0:e979170e02e7 3914
ashleymills 0:e979170e02e7 3915 for (x = 0; x < DIGIT_BIT; x++) {
ashleymills 0:e979170e02e7 3916 if (b == (((mp_digit)1)<<x)) {
ashleymills 0:e979170e02e7 3917 *p = x;
ashleymills 0:e979170e02e7 3918 return 1;
ashleymills 0:e979170e02e7 3919 }
ashleymills 0:e979170e02e7 3920 }
ashleymills 0:e979170e02e7 3921 return 0;
ashleymills 0:e979170e02e7 3922 }
ashleymills 0:e979170e02e7 3923
ashleymills 0:e979170e02e7 3924 /* single digit division (based on routine from MPI) */
ashleymills 0:e979170e02e7 3925 static int mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d)
ashleymills 0:e979170e02e7 3926 {
ashleymills 0:e979170e02e7 3927 mp_int q;
ashleymills 0:e979170e02e7 3928 mp_word w;
ashleymills 0:e979170e02e7 3929 mp_digit t;
ashleymills 0:e979170e02e7 3930 int res, ix;
ashleymills 0:e979170e02e7 3931
ashleymills 0:e979170e02e7 3932 /* cannot divide by zero */
ashleymills 0:e979170e02e7 3933 if (b == 0) {
ashleymills 0:e979170e02e7 3934 return MP_VAL;
ashleymills 0:e979170e02e7 3935 }
ashleymills 0:e979170e02e7 3936
ashleymills 0:e979170e02e7 3937 /* quick outs */
ashleymills 0:e979170e02e7 3938 if (b == 1 || mp_iszero(a) == 1) {
ashleymills 0:e979170e02e7 3939 if (d != NULL) {
ashleymills 0:e979170e02e7 3940 *d = 0;
ashleymills 0:e979170e02e7 3941 }
ashleymills 0:e979170e02e7 3942 if (c != NULL) {
ashleymills 0:e979170e02e7 3943 return mp_copy(a, c);
ashleymills 0:e979170e02e7 3944 }
ashleymills 0:e979170e02e7 3945 return MP_OKAY;
ashleymills 0:e979170e02e7 3946 }
ashleymills 0:e979170e02e7 3947
ashleymills 0:e979170e02e7 3948 /* power of two ? */
ashleymills 0:e979170e02e7 3949 if (s_is_power_of_two(b, &ix) == 1) {
ashleymills 0:e979170e02e7 3950 if (d != NULL) {
ashleymills 0:e979170e02e7 3951 *d = a->dp[0] & ((((mp_digit)1)<<ix) - 1);
ashleymills 0:e979170e02e7 3952 }
ashleymills 0:e979170e02e7 3953 if (c != NULL) {
ashleymills 0:e979170e02e7 3954 return mp_div_2d(a, ix, c, NULL);
ashleymills 0:e979170e02e7 3955 }
ashleymills 0:e979170e02e7 3956 return MP_OKAY;
ashleymills 0:e979170e02e7 3957 }
ashleymills 0:e979170e02e7 3958
ashleymills 0:e979170e02e7 3959 #ifdef BN_MP_DIV_3_C
ashleymills 0:e979170e02e7 3960 /* three? */
ashleymills 0:e979170e02e7 3961 if (b == 3) {
ashleymills 0:e979170e02e7 3962 return mp_div_3(a, c, d);
ashleymills 0:e979170e02e7 3963 }
ashleymills 0:e979170e02e7 3964 #endif
ashleymills 0:e979170e02e7 3965
ashleymills 0:e979170e02e7 3966 /* no easy answer [c'est la vie]. Just division */
ashleymills 0:e979170e02e7 3967 if ((res = mp_init_size(&q, a->used)) != MP_OKAY) {
ashleymills 0:e979170e02e7 3968 return res;
ashleymills 0:e979170e02e7 3969 }
ashleymills 0:e979170e02e7 3970
ashleymills 0:e979170e02e7 3971 q.used = a->used;
ashleymills 0:e979170e02e7 3972 q.sign = a->sign;
ashleymills 0:e979170e02e7 3973 w = 0;
ashleymills 0:e979170e02e7 3974 for (ix = a->used - 1; ix >= 0; ix--) {
ashleymills 0:e979170e02e7 3975 w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]);
ashleymills 0:e979170e02e7 3976
ashleymills 0:e979170e02e7 3977 if (w >= b) {
ashleymills 0:e979170e02e7 3978 t = (mp_digit)(w / b);
ashleymills 0:e979170e02e7 3979 w -= ((mp_word)t) * ((mp_word)b);
ashleymills 0:e979170e02e7 3980 } else {
ashleymills 0:e979170e02e7 3981 t = 0;
ashleymills 0:e979170e02e7 3982 }
ashleymills 0:e979170e02e7 3983 q.dp[ix] = (mp_digit)t;
ashleymills 0:e979170e02e7 3984 }
ashleymills 0:e979170e02e7 3985
ashleymills 0:e979170e02e7 3986 if (d != NULL) {
ashleymills 0:e979170e02e7 3987 *d = (mp_digit)w;
ashleymills 0:e979170e02e7 3988 }
ashleymills 0:e979170e02e7 3989
ashleymills 0:e979170e02e7 3990 if (c != NULL) {
ashleymills 0:e979170e02e7 3991 mp_clamp(&q);
ashleymills 0:e979170e02e7 3992 mp_exch(&q, c);
ashleymills 0:e979170e02e7 3993 }
ashleymills 0:e979170e02e7 3994 mp_clear(&q);
ashleymills 0:e979170e02e7 3995
ashleymills 0:e979170e02e7 3996 return res;
ashleymills 0:e979170e02e7 3997 }
ashleymills 0:e979170e02e7 3998
ashleymills 0:e979170e02e7 3999
ashleymills 0:e979170e02e7 4000 static int mp_mod_d (mp_int * a, mp_digit b, mp_digit * c)
ashleymills 0:e979170e02e7 4001 {
ashleymills 0:e979170e02e7 4002 return mp_div_d(a, b, NULL, c);
ashleymills 0:e979170e02e7 4003 }
ashleymills 0:e979170e02e7 4004
ashleymills 0:e979170e02e7 4005
ashleymills 0:e979170e02e7 4006 const mp_digit ltm_prime_tab[] = {
ashleymills 0:e979170e02e7 4007 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
ashleymills 0:e979170e02e7 4008 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
ashleymills 0:e979170e02e7 4009 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
ashleymills 0:e979170e02e7 4010 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F,
ashleymills 0:e979170e02e7 4011 #ifndef MP_8BIT
ashleymills 0:e979170e02e7 4012 0x0083,
ashleymills 0:e979170e02e7 4013 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD,
ashleymills 0:e979170e02e7 4014 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF,
ashleymills 0:e979170e02e7 4015 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107,
ashleymills 0:e979170e02e7 4016 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137,
ashleymills 0:e979170e02e7 4017
ashleymills 0:e979170e02e7 4018 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167,
ashleymills 0:e979170e02e7 4019 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199,
ashleymills 0:e979170e02e7 4020 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9,
ashleymills 0:e979170e02e7 4021 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7,
ashleymills 0:e979170e02e7 4022 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239,
ashleymills 0:e979170e02e7 4023 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265,
ashleymills 0:e979170e02e7 4024 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293,
ashleymills 0:e979170e02e7 4025 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF,
ashleymills 0:e979170e02e7 4026
ashleymills 0:e979170e02e7 4027 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301,
ashleymills 0:e979170e02e7 4028 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B,
ashleymills 0:e979170e02e7 4029 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371,
ashleymills 0:e979170e02e7 4030 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD,
ashleymills 0:e979170e02e7 4031 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5,
ashleymills 0:e979170e02e7 4032 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419,
ashleymills 0:e979170e02e7 4033 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449,
ashleymills 0:e979170e02e7 4034 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B,
ashleymills 0:e979170e02e7 4035
ashleymills 0:e979170e02e7 4036 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7,
ashleymills 0:e979170e02e7 4037 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503,
ashleymills 0:e979170e02e7 4038 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529,
ashleymills 0:e979170e02e7 4039 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F,
ashleymills 0:e979170e02e7 4040 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3,
ashleymills 0:e979170e02e7 4041 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7,
ashleymills 0:e979170e02e7 4042 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623,
ashleymills 0:e979170e02e7 4043 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653
ashleymills 0:e979170e02e7 4044 #endif
ashleymills 0:e979170e02e7 4045 };
ashleymills 0:e979170e02e7 4046
ashleymills 0:e979170e02e7 4047
ashleymills 0:e979170e02e7 4048 /* Miller-Rabin test of "a" to the base of "b" as described in
ashleymills 0:e979170e02e7 4049 * HAC pp. 139 Algorithm 4.24
ashleymills 0:e979170e02e7 4050 *
ashleymills 0:e979170e02e7 4051 * Sets result to 0 if definitely composite or 1 if probably prime.
ashleymills 0:e979170e02e7 4052 * Randomly the chance of error is no more than 1/4 and often
ashleymills 0:e979170e02e7 4053 * very much lower.
ashleymills 0:e979170e02e7 4054 */
ashleymills 0:e979170e02e7 4055 static int mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result)
ashleymills 0:e979170e02e7 4056 {
ashleymills 0:e979170e02e7 4057 mp_int n1, y, r;
ashleymills 0:e979170e02e7 4058 int s, j, err;
ashleymills 0:e979170e02e7 4059
ashleymills 0:e979170e02e7 4060 /* default */
ashleymills 0:e979170e02e7 4061 *result = MP_NO;
ashleymills 0:e979170e02e7 4062
ashleymills 0:e979170e02e7 4063 /* ensure b > 1 */
ashleymills 0:e979170e02e7 4064 if (mp_cmp_d(b, 1) != MP_GT) {
ashleymills 0:e979170e02e7 4065 return MP_VAL;
ashleymills 0:e979170e02e7 4066 }
ashleymills 0:e979170e02e7 4067
ashleymills 0:e979170e02e7 4068 /* get n1 = a - 1 */
ashleymills 0:e979170e02e7 4069 if ((err = mp_init_copy (&n1, a)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4070 return err;
ashleymills 0:e979170e02e7 4071 }
ashleymills 0:e979170e02e7 4072 if ((err = mp_sub_d (&n1, 1, &n1)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4073 goto LBL_N1;
ashleymills 0:e979170e02e7 4074 }
ashleymills 0:e979170e02e7 4075
ashleymills 0:e979170e02e7 4076 /* set 2**s * r = n1 */
ashleymills 0:e979170e02e7 4077 if ((err = mp_init_copy (&r, &n1)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4078 goto LBL_N1;
ashleymills 0:e979170e02e7 4079 }
ashleymills 0:e979170e02e7 4080
ashleymills 0:e979170e02e7 4081 /* count the number of least significant bits
ashleymills 0:e979170e02e7 4082 * which are zero
ashleymills 0:e979170e02e7 4083 */
ashleymills 0:e979170e02e7 4084 s = mp_cnt_lsb(&r);
ashleymills 0:e979170e02e7 4085
ashleymills 0:e979170e02e7 4086 /* now divide n - 1 by 2**s */
ashleymills 0:e979170e02e7 4087 if ((err = mp_div_2d (&r, s, &r, NULL)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4088 goto LBL_R;
ashleymills 0:e979170e02e7 4089 }
ashleymills 0:e979170e02e7 4090
ashleymills 0:e979170e02e7 4091 /* compute y = b**r mod a */
ashleymills 0:e979170e02e7 4092 if ((err = mp_init (&y)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4093 goto LBL_R;
ashleymills 0:e979170e02e7 4094 }
ashleymills 0:e979170e02e7 4095 if ((err = mp_exptmod (b, &r, a, &y)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4096 goto LBL_Y;
ashleymills 0:e979170e02e7 4097 }
ashleymills 0:e979170e02e7 4098
ashleymills 0:e979170e02e7 4099 /* if y != 1 and y != n1 do */
ashleymills 0:e979170e02e7 4100 if (mp_cmp_d (&y, 1) != MP_EQ && mp_cmp (&y, &n1) != MP_EQ) {
ashleymills 0:e979170e02e7 4101 j = 1;
ashleymills 0:e979170e02e7 4102 /* while j <= s-1 and y != n1 */
ashleymills 0:e979170e02e7 4103 while ((j <= (s - 1)) && mp_cmp (&y, &n1) != MP_EQ) {
ashleymills 0:e979170e02e7 4104 if ((err = mp_sqrmod (&y, a, &y)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4105 goto LBL_Y;
ashleymills 0:e979170e02e7 4106 }
ashleymills 0:e979170e02e7 4107
ashleymills 0:e979170e02e7 4108 /* if y == 1 then composite */
ashleymills 0:e979170e02e7 4109 if (mp_cmp_d (&y, 1) == MP_EQ) {
ashleymills 0:e979170e02e7 4110 goto LBL_Y;
ashleymills 0:e979170e02e7 4111 }
ashleymills 0:e979170e02e7 4112
ashleymills 0:e979170e02e7 4113 ++j;
ashleymills 0:e979170e02e7 4114 }
ashleymills 0:e979170e02e7 4115
ashleymills 0:e979170e02e7 4116 /* if y != n1 then composite */
ashleymills 0:e979170e02e7 4117 if (mp_cmp (&y, &n1) != MP_EQ) {
ashleymills 0:e979170e02e7 4118 goto LBL_Y;
ashleymills 0:e979170e02e7 4119 }
ashleymills 0:e979170e02e7 4120 }
ashleymills 0:e979170e02e7 4121
ashleymills 0:e979170e02e7 4122 /* probably prime now */
ashleymills 0:e979170e02e7 4123 *result = MP_YES;
ashleymills 0:e979170e02e7 4124 LBL_Y:mp_clear (&y);
ashleymills 0:e979170e02e7 4125 LBL_R:mp_clear (&r);
ashleymills 0:e979170e02e7 4126 LBL_N1:mp_clear (&n1);
ashleymills 0:e979170e02e7 4127 return err;
ashleymills 0:e979170e02e7 4128 }
ashleymills 0:e979170e02e7 4129
ashleymills 0:e979170e02e7 4130
ashleymills 0:e979170e02e7 4131 /* determines if an integers is divisible by one
ashleymills 0:e979170e02e7 4132 * of the first PRIME_SIZE primes or not
ashleymills 0:e979170e02e7 4133 *
ashleymills 0:e979170e02e7 4134 * sets result to 0 if not, 1 if yes
ashleymills 0:e979170e02e7 4135 */
ashleymills 0:e979170e02e7 4136 static int mp_prime_is_divisible (mp_int * a, int *result)
ashleymills 0:e979170e02e7 4137 {
ashleymills 0:e979170e02e7 4138 int err, ix;
ashleymills 0:e979170e02e7 4139 mp_digit res;
ashleymills 0:e979170e02e7 4140
ashleymills 0:e979170e02e7 4141 /* default to not */
ashleymills 0:e979170e02e7 4142 *result = MP_NO;
ashleymills 0:e979170e02e7 4143
ashleymills 0:e979170e02e7 4144 for (ix = 0; ix < PRIME_SIZE; ix++) {
ashleymills 0:e979170e02e7 4145 /* what is a mod LBL_prime_tab[ix] */
ashleymills 0:e979170e02e7 4146 if ((err = mp_mod_d (a, ltm_prime_tab[ix], &res)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4147 return err;
ashleymills 0:e979170e02e7 4148 }
ashleymills 0:e979170e02e7 4149
ashleymills 0:e979170e02e7 4150 /* is the residue zero? */
ashleymills 0:e979170e02e7 4151 if (res == 0) {
ashleymills 0:e979170e02e7 4152 *result = MP_YES;
ashleymills 0:e979170e02e7 4153 return MP_OKAY;
ashleymills 0:e979170e02e7 4154 }
ashleymills 0:e979170e02e7 4155 }
ashleymills 0:e979170e02e7 4156
ashleymills 0:e979170e02e7 4157 return MP_OKAY;
ashleymills 0:e979170e02e7 4158 }
ashleymills 0:e979170e02e7 4159
ashleymills 0:e979170e02e7 4160
ashleymills 0:e979170e02e7 4161 /*
ashleymills 0:e979170e02e7 4162 * Sets result to 1 if probably prime, 0 otherwise
ashleymills 0:e979170e02e7 4163 */
ashleymills 0:e979170e02e7 4164 int mp_prime_is_prime (mp_int * a, int t, int *result)
ashleymills 0:e979170e02e7 4165 {
ashleymills 0:e979170e02e7 4166 mp_int b;
ashleymills 0:e979170e02e7 4167 int ix, err, res;
ashleymills 0:e979170e02e7 4168
ashleymills 0:e979170e02e7 4169 /* default to no */
ashleymills 0:e979170e02e7 4170 *result = MP_NO;
ashleymills 0:e979170e02e7 4171
ashleymills 0:e979170e02e7 4172 /* valid value of t? */
ashleymills 0:e979170e02e7 4173 if (t <= 0 || t > PRIME_SIZE) {
ashleymills 0:e979170e02e7 4174 return MP_VAL;
ashleymills 0:e979170e02e7 4175 }
ashleymills 0:e979170e02e7 4176
ashleymills 0:e979170e02e7 4177 /* is the input equal to one of the primes in the table? */
ashleymills 0:e979170e02e7 4178 for (ix = 0; ix < PRIME_SIZE; ix++) {
ashleymills 0:e979170e02e7 4179 if (mp_cmp_d(a, ltm_prime_tab[ix]) == MP_EQ) {
ashleymills 0:e979170e02e7 4180 *result = 1;
ashleymills 0:e979170e02e7 4181 return MP_OKAY;
ashleymills 0:e979170e02e7 4182 }
ashleymills 0:e979170e02e7 4183 }
ashleymills 0:e979170e02e7 4184
ashleymills 0:e979170e02e7 4185 /* first perform trial division */
ashleymills 0:e979170e02e7 4186 if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4187 return err;
ashleymills 0:e979170e02e7 4188 }
ashleymills 0:e979170e02e7 4189
ashleymills 0:e979170e02e7 4190 /* return if it was trivially divisible */
ashleymills 0:e979170e02e7 4191 if (res == MP_YES) {
ashleymills 0:e979170e02e7 4192 return MP_OKAY;
ashleymills 0:e979170e02e7 4193 }
ashleymills 0:e979170e02e7 4194
ashleymills 0:e979170e02e7 4195 /* now perform the miller-rabin rounds */
ashleymills 0:e979170e02e7 4196 if ((err = mp_init (&b)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4197 return err;
ashleymills 0:e979170e02e7 4198 }
ashleymills 0:e979170e02e7 4199
ashleymills 0:e979170e02e7 4200 for (ix = 0; ix < t; ix++) {
ashleymills 0:e979170e02e7 4201 /* set the prime */
ashleymills 0:e979170e02e7 4202 mp_set (&b, ltm_prime_tab[ix]);
ashleymills 0:e979170e02e7 4203
ashleymills 0:e979170e02e7 4204 if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4205 goto LBL_B;
ashleymills 0:e979170e02e7 4206 }
ashleymills 0:e979170e02e7 4207
ashleymills 0:e979170e02e7 4208 if (res == MP_NO) {
ashleymills 0:e979170e02e7 4209 goto LBL_B;
ashleymills 0:e979170e02e7 4210 }
ashleymills 0:e979170e02e7 4211 }
ashleymills 0:e979170e02e7 4212
ashleymills 0:e979170e02e7 4213 /* passed the test */
ashleymills 0:e979170e02e7 4214 *result = MP_YES;
ashleymills 0:e979170e02e7 4215 LBL_B:mp_clear (&b);
ashleymills 0:e979170e02e7 4216 return err;
ashleymills 0:e979170e02e7 4217 }
ashleymills 0:e979170e02e7 4218
ashleymills 0:e979170e02e7 4219
ashleymills 0:e979170e02e7 4220 /* computes least common multiple as |a*b|/(a, b) */
ashleymills 0:e979170e02e7 4221 int mp_lcm (mp_int * a, mp_int * b, mp_int * c)
ashleymills 0:e979170e02e7 4222 {
ashleymills 0:e979170e02e7 4223 int res;
ashleymills 0:e979170e02e7 4224 mp_int t1, t2;
ashleymills 0:e979170e02e7 4225
ashleymills 0:e979170e02e7 4226
ashleymills 0:e979170e02e7 4227 if ((res = mp_init_multi (&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4228 return res;
ashleymills 0:e979170e02e7 4229 }
ashleymills 0:e979170e02e7 4230
ashleymills 0:e979170e02e7 4231 /* t1 = get the GCD of the two inputs */
ashleymills 0:e979170e02e7 4232 if ((res = mp_gcd (a, b, &t1)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4233 goto LBL_T;
ashleymills 0:e979170e02e7 4234 }
ashleymills 0:e979170e02e7 4235
ashleymills 0:e979170e02e7 4236 /* divide the smallest by the GCD */
ashleymills 0:e979170e02e7 4237 if (mp_cmp_mag(a, b) == MP_LT) {
ashleymills 0:e979170e02e7 4238 /* store quotient in t2 such that t2 * b is the LCM */
ashleymills 0:e979170e02e7 4239 if ((res = mp_div(a, &t1, &t2, NULL)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4240 goto LBL_T;
ashleymills 0:e979170e02e7 4241 }
ashleymills 0:e979170e02e7 4242 res = mp_mul(b, &t2, c);
ashleymills 0:e979170e02e7 4243 } else {
ashleymills 0:e979170e02e7 4244 /* store quotient in t2 such that t2 * a is the LCM */
ashleymills 0:e979170e02e7 4245 if ((res = mp_div(b, &t1, &t2, NULL)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4246 goto LBL_T;
ashleymills 0:e979170e02e7 4247 }
ashleymills 0:e979170e02e7 4248 res = mp_mul(a, &t2, c);
ashleymills 0:e979170e02e7 4249 }
ashleymills 0:e979170e02e7 4250
ashleymills 0:e979170e02e7 4251 /* fix the sign to positive */
ashleymills 0:e979170e02e7 4252 c->sign = MP_ZPOS;
ashleymills 0:e979170e02e7 4253
ashleymills 0:e979170e02e7 4254 LBL_T:
ashleymills 0:e979170e02e7 4255 mp_clear(&t1);
ashleymills 0:e979170e02e7 4256 mp_clear(&t2);
ashleymills 0:e979170e02e7 4257 return res;
ashleymills 0:e979170e02e7 4258 }
ashleymills 0:e979170e02e7 4259
ashleymills 0:e979170e02e7 4260
ashleymills 0:e979170e02e7 4261 static const int lnz[16] = {
ashleymills 0:e979170e02e7 4262 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
ashleymills 0:e979170e02e7 4263 };
ashleymills 0:e979170e02e7 4264
ashleymills 0:e979170e02e7 4265 /* Counts the number of lsbs which are zero before the first zero bit */
ashleymills 0:e979170e02e7 4266 int mp_cnt_lsb(mp_int *a)
ashleymills 0:e979170e02e7 4267 {
ashleymills 0:e979170e02e7 4268 int x;
ashleymills 0:e979170e02e7 4269 mp_digit q, qq;
ashleymills 0:e979170e02e7 4270
ashleymills 0:e979170e02e7 4271 /* easy out */
ashleymills 0:e979170e02e7 4272 if (mp_iszero(a) == 1) {
ashleymills 0:e979170e02e7 4273 return 0;
ashleymills 0:e979170e02e7 4274 }
ashleymills 0:e979170e02e7 4275
ashleymills 0:e979170e02e7 4276 /* scan lower digits until non-zero */
ashleymills 0:e979170e02e7 4277 for (x = 0; x < a->used && a->dp[x] == 0; x++);
ashleymills 0:e979170e02e7 4278 q = a->dp[x];
ashleymills 0:e979170e02e7 4279 x *= DIGIT_BIT;
ashleymills 0:e979170e02e7 4280
ashleymills 0:e979170e02e7 4281 /* now scan this digit until a 1 is found */
ashleymills 0:e979170e02e7 4282 if ((q & 1) == 0) {
ashleymills 0:e979170e02e7 4283 do {
ashleymills 0:e979170e02e7 4284 qq = q & 15;
ashleymills 0:e979170e02e7 4285 x += lnz[qq];
ashleymills 0:e979170e02e7 4286 q >>= 4;
ashleymills 0:e979170e02e7 4287 } while (qq == 0);
ashleymills 0:e979170e02e7 4288 }
ashleymills 0:e979170e02e7 4289 return x;
ashleymills 0:e979170e02e7 4290 }
ashleymills 0:e979170e02e7 4291
ashleymills 0:e979170e02e7 4292
ashleymills 0:e979170e02e7 4293 /* Greatest Common Divisor using the binary method */
ashleymills 0:e979170e02e7 4294 int mp_gcd (mp_int * a, mp_int * b, mp_int * c)
ashleymills 0:e979170e02e7 4295 {
ashleymills 0:e979170e02e7 4296 mp_int u, v;
ashleymills 0:e979170e02e7 4297 int k, u_lsb, v_lsb, res;
ashleymills 0:e979170e02e7 4298
ashleymills 0:e979170e02e7 4299 /* either zero than gcd is the largest */
ashleymills 0:e979170e02e7 4300 if (mp_iszero (a) == MP_YES) {
ashleymills 0:e979170e02e7 4301 return mp_abs (b, c);
ashleymills 0:e979170e02e7 4302 }
ashleymills 0:e979170e02e7 4303 if (mp_iszero (b) == MP_YES) {
ashleymills 0:e979170e02e7 4304 return mp_abs (a, c);
ashleymills 0:e979170e02e7 4305 }
ashleymills 0:e979170e02e7 4306
ashleymills 0:e979170e02e7 4307 /* get copies of a and b we can modify */
ashleymills 0:e979170e02e7 4308 if ((res = mp_init_copy (&u, a)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4309 return res;
ashleymills 0:e979170e02e7 4310 }
ashleymills 0:e979170e02e7 4311
ashleymills 0:e979170e02e7 4312 if ((res = mp_init_copy (&v, b)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4313 goto LBL_U;
ashleymills 0:e979170e02e7 4314 }
ashleymills 0:e979170e02e7 4315
ashleymills 0:e979170e02e7 4316 /* must be positive for the remainder of the algorithm */
ashleymills 0:e979170e02e7 4317 u.sign = v.sign = MP_ZPOS;
ashleymills 0:e979170e02e7 4318
ashleymills 0:e979170e02e7 4319 /* B1. Find the common power of two for u and v */
ashleymills 0:e979170e02e7 4320 u_lsb = mp_cnt_lsb(&u);
ashleymills 0:e979170e02e7 4321 v_lsb = mp_cnt_lsb(&v);
ashleymills 0:e979170e02e7 4322 k = MIN(u_lsb, v_lsb);
ashleymills 0:e979170e02e7 4323
ashleymills 0:e979170e02e7 4324 if (k > 0) {
ashleymills 0:e979170e02e7 4325 /* divide the power of two out */
ashleymills 0:e979170e02e7 4326 if ((res = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4327 goto LBL_V;
ashleymills 0:e979170e02e7 4328 }
ashleymills 0:e979170e02e7 4329
ashleymills 0:e979170e02e7 4330 if ((res = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4331 goto LBL_V;
ashleymills 0:e979170e02e7 4332 }
ashleymills 0:e979170e02e7 4333 }
ashleymills 0:e979170e02e7 4334
ashleymills 0:e979170e02e7 4335 /* divide any remaining factors of two out */
ashleymills 0:e979170e02e7 4336 if (u_lsb != k) {
ashleymills 0:e979170e02e7 4337 if ((res = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4338 goto LBL_V;
ashleymills 0:e979170e02e7 4339 }
ashleymills 0:e979170e02e7 4340 }
ashleymills 0:e979170e02e7 4341
ashleymills 0:e979170e02e7 4342 if (v_lsb != k) {
ashleymills 0:e979170e02e7 4343 if ((res = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4344 goto LBL_V;
ashleymills 0:e979170e02e7 4345 }
ashleymills 0:e979170e02e7 4346 }
ashleymills 0:e979170e02e7 4347
ashleymills 0:e979170e02e7 4348 while (mp_iszero(&v) == 0) {
ashleymills 0:e979170e02e7 4349 /* make sure v is the largest */
ashleymills 0:e979170e02e7 4350 if (mp_cmp_mag(&u, &v) == MP_GT) {
ashleymills 0:e979170e02e7 4351 /* swap u and v to make sure v is >= u */
ashleymills 0:e979170e02e7 4352 mp_exch(&u, &v);
ashleymills 0:e979170e02e7 4353 }
ashleymills 0:e979170e02e7 4354
ashleymills 0:e979170e02e7 4355 /* subtract smallest from largest */
ashleymills 0:e979170e02e7 4356 if ((res = s_mp_sub(&v, &u, &v)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4357 goto LBL_V;
ashleymills 0:e979170e02e7 4358 }
ashleymills 0:e979170e02e7 4359
ashleymills 0:e979170e02e7 4360 /* Divide out all factors of two */
ashleymills 0:e979170e02e7 4361 if ((res = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4362 goto LBL_V;
ashleymills 0:e979170e02e7 4363 }
ashleymills 0:e979170e02e7 4364 }
ashleymills 0:e979170e02e7 4365
ashleymills 0:e979170e02e7 4366 /* multiply by 2**k which we divided out at the beginning */
ashleymills 0:e979170e02e7 4367 if ((res = mp_mul_2d (&u, k, c)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4368 goto LBL_V;
ashleymills 0:e979170e02e7 4369 }
ashleymills 0:e979170e02e7 4370 c->sign = MP_ZPOS;
ashleymills 0:e979170e02e7 4371 res = MP_OKAY;
ashleymills 0:e979170e02e7 4372 LBL_V:mp_clear (&u);
ashleymills 0:e979170e02e7 4373 LBL_U:mp_clear (&v);
ashleymills 0:e979170e02e7 4374 return res;
ashleymills 0:e979170e02e7 4375 }
ashleymills 0:e979170e02e7 4376
ashleymills 0:e979170e02e7 4377
ashleymills 0:e979170e02e7 4378
ashleymills 0:e979170e02e7 4379 #endif /* CYASSL_KEY_GEN */
ashleymills 0:e979170e02e7 4380
ashleymills 0:e979170e02e7 4381
ashleymills 0:e979170e02e7 4382 #ifdef HAVE_ECC
ashleymills 0:e979170e02e7 4383
ashleymills 0:e979170e02e7 4384 /* chars used in radix conversions */
ashleymills 0:e979170e02e7 4385 const char *mp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
ashleymills 0:e979170e02e7 4386
ashleymills 0:e979170e02e7 4387 /* read a string [ASCII] in a given radix */
ashleymills 0:e979170e02e7 4388 int mp_read_radix (mp_int * a, const char *str, int radix)
ashleymills 0:e979170e02e7 4389 {
ashleymills 0:e979170e02e7 4390 int y, res, neg;
ashleymills 0:e979170e02e7 4391 char ch;
ashleymills 0:e979170e02e7 4392
ashleymills 0:e979170e02e7 4393 /* zero the digit bignum */
ashleymills 0:e979170e02e7 4394 mp_zero(a);
ashleymills 0:e979170e02e7 4395
ashleymills 0:e979170e02e7 4396 /* make sure the radix is ok */
ashleymills 0:e979170e02e7 4397 if (radix < 2 || radix > 64) {
ashleymills 0:e979170e02e7 4398 return MP_VAL;
ashleymills 0:e979170e02e7 4399 }
ashleymills 0:e979170e02e7 4400
ashleymills 0:e979170e02e7 4401 /* if the leading digit is a
ashleymills 0:e979170e02e7 4402 * minus set the sign to negative.
ashleymills 0:e979170e02e7 4403 */
ashleymills 0:e979170e02e7 4404 if (*str == '-') {
ashleymills 0:e979170e02e7 4405 ++str;
ashleymills 0:e979170e02e7 4406 neg = MP_NEG;
ashleymills 0:e979170e02e7 4407 } else {
ashleymills 0:e979170e02e7 4408 neg = MP_ZPOS;
ashleymills 0:e979170e02e7 4409 }
ashleymills 0:e979170e02e7 4410
ashleymills 0:e979170e02e7 4411 /* set the integer to the default of zero */
ashleymills 0:e979170e02e7 4412 mp_zero (a);
ashleymills 0:e979170e02e7 4413
ashleymills 0:e979170e02e7 4414 /* process each digit of the string */
ashleymills 0:e979170e02e7 4415 while (*str) {
ashleymills 0:e979170e02e7 4416 /* if the radix < 36 the conversion is case insensitive
ashleymills 0:e979170e02e7 4417 * this allows numbers like 1AB and 1ab to represent the same value
ashleymills 0:e979170e02e7 4418 * [e.g. in hex]
ashleymills 0:e979170e02e7 4419 */
ashleymills 0:e979170e02e7 4420 ch = (char) ((radix < 36) ? XTOUPPER(*str) : *str);
ashleymills 0:e979170e02e7 4421 for (y = 0; y < 64; y++) {
ashleymills 0:e979170e02e7 4422 if (ch == mp_s_rmap[y]) {
ashleymills 0:e979170e02e7 4423 break;
ashleymills 0:e979170e02e7 4424 }
ashleymills 0:e979170e02e7 4425 }
ashleymills 0:e979170e02e7 4426
ashleymills 0:e979170e02e7 4427 /* if the char was found in the map
ashleymills 0:e979170e02e7 4428 * and is less than the given radix add it
ashleymills 0:e979170e02e7 4429 * to the number, otherwise exit the loop.
ashleymills 0:e979170e02e7 4430 */
ashleymills 0:e979170e02e7 4431 if (y < radix) {
ashleymills 0:e979170e02e7 4432 if ((res = mp_mul_d (a, (mp_digit) radix, a)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4433 return res;
ashleymills 0:e979170e02e7 4434 }
ashleymills 0:e979170e02e7 4435 if ((res = mp_add_d (a, (mp_digit) y, a)) != MP_OKAY) {
ashleymills 0:e979170e02e7 4436 return res;
ashleymills 0:e979170e02e7 4437 }
ashleymills 0:e979170e02e7 4438 } else {
ashleymills 0:e979170e02e7 4439 break;
ashleymills 0:e979170e02e7 4440 }
ashleymills 0:e979170e02e7 4441 ++str;
ashleymills 0:e979170e02e7 4442 }
ashleymills 0:e979170e02e7 4443
ashleymills 0:e979170e02e7 4444 /* set the sign only if a != 0 */
ashleymills 0:e979170e02e7 4445 if (mp_iszero(a) != 1) {
ashleymills 0:e979170e02e7 4446 a->sign = neg;
ashleymills 0:e979170e02e7 4447 }
ashleymills 0:e979170e02e7 4448 return MP_OKAY;
ashleymills 0:e979170e02e7 4449 }
ashleymills 0:e979170e02e7 4450
ashleymills 0:e979170e02e7 4451 #endif /* HAVE_ECC */
ashleymills 0:e979170e02e7 4452
ashleymills 0:e979170e02e7 4453 #endif /* USE_FAST_MATH */
ashleymills 0:e979170e02e7 4454