1 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com) 2 * All rights reserved. 3 * 4 * This package is an SSL implementation written 5 * by Eric Young (eay (at) cryptsoft.com). 6 * The implementation was written so as to conform with Netscapes SSL. 7 * 8 * This library is free for commercial and non-commercial use as long as 9 * the following conditions are aheared to. The following conditions 10 * apply to all code found in this distribution, be it the RC4, RSA, 11 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 12 * included with this distribution is covered by the same copyright terms 13 * except that the holder is Tim Hudson (tjh (at) cryptsoft.com). 14 * 15 * Copyright remains Eric Young's, and as such any Copyright notices in 16 * the code are not to be removed. 17 * If this package is used in a product, Eric Young should be given attribution 18 * as the author of the parts of the library used. 19 * This can be in the form of a textual message at program startup or 20 * in documentation (online or textual) provided with the package. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 1. Redistributions of source code must retain the copyright 26 * notice, this list of conditions and the following disclaimer. 27 * 2. Redistributions in binary form must reproduce the above copyright 28 * notice, this list of conditions and the following disclaimer in the 29 * documentation and/or other materials provided with the distribution. 30 * 3. All advertising materials mentioning features or use of this software 31 * must display the following acknowledgement: 32 * "This product includes cryptographic software written by 33 * Eric Young (eay (at) cryptsoft.com)" 34 * The word 'cryptographic' can be left out if the rouines from the library 35 * being used are not cryptographic related :-). 36 * 4. If you include any Windows specific code (or a derivative thereof) from 37 * the apps directory (application code) you must include an acknowledgement: 38 * "This product includes software written by Tim Hudson (tjh (at) cryptsoft.com)" 39 * 40 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 43 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 50 * SUCH DAMAGE. 51 * 52 * The licence and distribution terms for any publically available version or 53 * derivative of this code cannot be changed. i.e. this code cannot simply be 54 * copied and put under another distribution licence 55 * [including the GNU Public Licence.] */ 56 57 #include <openssl/bn.h> 58 59 #include <string.h> 60 61 #include <openssl/err.h> 62 #include <openssl/mem.h> 63 64 #include "internal.h" 65 66 67 int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { 68 const BIGNUM *tmp; 69 int a_neg = a->neg, ret; 70 71 /* a + b a+b 72 * a + -b a-b 73 * -a + b b-a 74 * -a + -b -(a+b) 75 */ 76 if (a_neg ^ b->neg) { 77 /* only one is negative */ 78 if (a_neg) { 79 tmp = a; 80 a = b; 81 b = tmp; 82 } 83 84 /* we are now a - b */ 85 if (BN_ucmp(a, b) < 0) { 86 if (!BN_usub(r, b, a)) { 87 return 0; 88 } 89 r->neg = 1; 90 } else { 91 if (!BN_usub(r, a, b)) { 92 return 0; 93 } 94 r->neg = 0; 95 } 96 return 1; 97 } 98 99 ret = BN_uadd(r, a, b); 100 r->neg = a_neg; 101 return ret; 102 } 103 104 int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { 105 int max, min, dif; 106 BN_ULONG *ap, *bp, *rp, carry, t1, t2; 107 const BIGNUM *tmp; 108 109 if (a->top < b->top) { 110 tmp = a; 111 a = b; 112 b = tmp; 113 } 114 max = a->top; 115 min = b->top; 116 dif = max - min; 117 118 if (bn_wexpand(r, max + 1) == NULL) { 119 return 0; 120 } 121 122 r->top = max; 123 124 ap = a->d; 125 bp = b->d; 126 rp = r->d; 127 128 carry = bn_add_words(rp, ap, bp, min); 129 rp += min; 130 ap += min; 131 bp += min; 132 133 if (carry) { 134 while (dif) { 135 dif--; 136 t1 = *(ap++); 137 t2 = (t1 + 1) & BN_MASK2; 138 *(rp++) = t2; 139 if (t2) { 140 carry = 0; 141 break; 142 } 143 } 144 if (carry) { 145 /* carry != 0 => dif == 0 */ 146 *rp = 1; 147 r->top++; 148 } 149 } 150 151 if (dif && rp != ap) { 152 while (dif--) { 153 /* copy remaining words if ap != rp */ 154 *(rp++) = *(ap++); 155 } 156 } 157 158 r->neg = 0; 159 return 1; 160 } 161 162 int BN_add_word(BIGNUM *a, BN_ULONG w) { 163 BN_ULONG l; 164 int i; 165 166 w &= BN_MASK2; 167 168 /* degenerate case: w is zero */ 169 if (!w) { 170 return 1; 171 } 172 173 /* degenerate case: a is zero */ 174 if (BN_is_zero(a)) { 175 return BN_set_word(a, w); 176 } 177 178 /* handle 'a' when negative */ 179 if (a->neg) { 180 a->neg = 0; 181 i = BN_sub_word(a, w); 182 if (!BN_is_zero(a)) { 183 a->neg = !(a->neg); 184 } 185 return i; 186 } 187 188 for (i = 0; w != 0 && i < a->top; i++) { 189 a->d[i] = l = (a->d[i] + w) & BN_MASK2; 190 w = (w > l) ? 1 : 0; 191 } 192 193 if (w && i == a->top) { 194 if (bn_wexpand(a, a->top + 1) == NULL) { 195 return 0; 196 } 197 a->top++; 198 a->d[i] = w; 199 } 200 201 return 1; 202 } 203 204 int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { 205 int max; 206 int add = 0, neg = 0; 207 const BIGNUM *tmp; 208 209 /* a - b a-b 210 * a - -b a+b 211 * -a - b -(a+b) 212 * -a - -b b-a 213 */ 214 if (a->neg) { 215 if (b->neg) { 216 tmp = a; 217 a = b; 218 b = tmp; 219 } else { 220 add = 1; 221 neg = 1; 222 } 223 } else { 224 if (b->neg) { 225 add = 1; 226 neg = 0; 227 } 228 } 229 230 if (add) { 231 if (!BN_uadd(r, a, b)) { 232 return 0; 233 } 234 235 r->neg = neg; 236 return 1; 237 } 238 239 /* We are actually doing a - b :-) */ 240 241 max = (a->top > b->top) ? a->top : b->top; 242 if (bn_wexpand(r, max) == NULL) { 243 return 0; 244 } 245 246 if (BN_ucmp(a, b) < 0) { 247 if (!BN_usub(r, b, a)) { 248 return 0; 249 } 250 r->neg = 1; 251 } else { 252 if (!BN_usub(r, a, b)) { 253 return 0; 254 } 255 r->neg = 0; 256 } 257 258 return 1; 259 } 260 261 int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { 262 int max, min, dif; 263 register BN_ULONG t1, t2, *ap, *bp, *rp; 264 int i, carry; 265 266 max = a->top; 267 min = b->top; 268 dif = max - min; 269 270 if (dif < 0) /* hmm... should not be happening */ 271 { 272 OPENSSL_PUT_ERROR(BN, BN_R_ARG2_LT_ARG3); 273 return 0; 274 } 275 276 if (bn_wexpand(r, max) == NULL) { 277 return 0; 278 } 279 280 ap = a->d; 281 bp = b->d; 282 rp = r->d; 283 284 carry = 0; 285 for (i = min; i != 0; i--) { 286 t1 = *(ap++); 287 t2 = *(bp++); 288 if (carry) { 289 carry = (t1 <= t2); 290 t1 = (t1 - t2 - 1) & BN_MASK2; 291 } else { 292 carry = (t1 < t2); 293 t1 = (t1 - t2) & BN_MASK2; 294 } 295 *(rp++) = t1 & BN_MASK2; 296 } 297 298 if (carry) /* subtracted */ 299 { 300 if (!dif) { 301 /* error: a < b */ 302 return 0; 303 } 304 305 while (dif) { 306 dif--; 307 t1 = *(ap++); 308 t2 = (t1 - 1) & BN_MASK2; 309 *(rp++) = t2; 310 if (t1) { 311 break; 312 } 313 } 314 } 315 316 if (dif > 0 && rp != ap) { 317 memcpy(rp, ap, sizeof(*rp) * dif); 318 } 319 320 r->top = max; 321 r->neg = 0; 322 bn_correct_top(r); 323 324 return 1; 325 } 326 327 int BN_sub_word(BIGNUM *a, BN_ULONG w) { 328 int i; 329 330 w &= BN_MASK2; 331 332 /* degenerate case: w is zero */ 333 if (!w) { 334 return 1; 335 } 336 337 /* degenerate case: a is zero */ 338 if (BN_is_zero(a)) { 339 i = BN_set_word(a, w); 340 if (i != 0) { 341 BN_set_negative(a, 1); 342 } 343 return i; 344 } 345 346 /* handle 'a' when negative */ 347 if (a->neg) { 348 a->neg = 0; 349 i = BN_add_word(a, w); 350 a->neg = 1; 351 return i; 352 } 353 354 if ((a->top == 1) && (a->d[0] < w)) { 355 a->d[0] = w - a->d[0]; 356 a->neg = 1; 357 return 1; 358 } 359 360 i = 0; 361 for (;;) { 362 if (a->d[i] >= w) { 363 a->d[i] -= w; 364 break; 365 } else { 366 a->d[i] = (a->d[i] - w) & BN_MASK2; 367 i++; 368 w = 1; 369 } 370 } 371 372 if ((a->d[i] == 0) && (i == (a->top - 1))) { 373 a->top--; 374 } 375 376 return 1; 377 } 378