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 if (a_neg ^ b->neg) { 76 // only one is negative 77 if (a_neg) { 78 tmp = a; 79 a = b; 80 b = tmp; 81 } 82 83 // we are now a - b 84 if (BN_ucmp(a, b) < 0) { 85 if (!BN_usub(r, b, a)) { 86 return 0; 87 } 88 r->neg = 1; 89 } else { 90 if (!BN_usub(r, a, b)) { 91 return 0; 92 } 93 r->neg = 0; 94 } 95 return 1; 96 } 97 98 ret = BN_uadd(r, a, b); 99 r->neg = a_neg; 100 return ret; 101 } 102 103 int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { 104 int max, min, dif; 105 BN_ULONG *ap, *bp, *rp, carry, t1, t2; 106 const BIGNUM *tmp; 107 108 if (a->top < b->top) { 109 tmp = a; 110 a = b; 111 b = tmp; 112 } 113 max = a->top; 114 min = b->top; 115 dif = max - min; 116 117 if (!bn_wexpand(r, max + 1)) { 118 return 0; 119 } 120 121 r->top = max; 122 123 ap = a->d; 124 bp = b->d; 125 rp = r->d; 126 127 carry = bn_add_words(rp, ap, bp, min); 128 rp += min; 129 ap += min; 130 bp += min; 131 132 if (carry) { 133 while (dif) { 134 dif--; 135 t1 = *(ap++); 136 t2 = t1 + 1; 137 *(rp++) = t2; 138 if (t2) { 139 carry = 0; 140 break; 141 } 142 } 143 if (carry) { 144 // carry != 0 => dif == 0 145 *rp = 1; 146 r->top++; 147 } 148 } 149 150 if (dif && rp != ap) { 151 while (dif--) { 152 // copy remaining words if ap != rp 153 *(rp++) = *(ap++); 154 } 155 } 156 157 r->neg = 0; 158 return 1; 159 } 160 161 int BN_add_word(BIGNUM *a, BN_ULONG w) { 162 BN_ULONG l; 163 int i; 164 165 // degenerate case: w is zero 166 if (!w) { 167 return 1; 168 } 169 170 // degenerate case: a is zero 171 if (BN_is_zero(a)) { 172 return BN_set_word(a, w); 173 } 174 175 // handle 'a' when negative 176 if (a->neg) { 177 a->neg = 0; 178 i = BN_sub_word(a, w); 179 if (!BN_is_zero(a)) { 180 a->neg = !(a->neg); 181 } 182 return i; 183 } 184 185 for (i = 0; w != 0 && i < a->top; i++) { 186 a->d[i] = l = a->d[i] + w; 187 w = (w > l) ? 1 : 0; 188 } 189 190 if (w && i == a->top) { 191 if (!bn_wexpand(a, a->top + 1)) { 192 return 0; 193 } 194 a->top++; 195 a->d[i] = w; 196 } 197 198 return 1; 199 } 200 201 int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { 202 int add = 0, neg = 0; 203 const BIGNUM *tmp; 204 205 // a - b a-b 206 // a - -b a+b 207 // -a - b -(a+b) 208 // -a - -b b-a 209 if (a->neg) { 210 if (b->neg) { 211 tmp = a; 212 a = b; 213 b = tmp; 214 } else { 215 add = 1; 216 neg = 1; 217 } 218 } else { 219 if (b->neg) { 220 add = 1; 221 neg = 0; 222 } 223 } 224 225 if (add) { 226 if (!BN_uadd(r, a, b)) { 227 return 0; 228 } 229 230 r->neg = neg; 231 return 1; 232 } 233 234 if (BN_ucmp(a, b) < 0) { 235 if (!BN_usub(r, b, a)) { 236 return 0; 237 } 238 r->neg = 1; 239 } else { 240 if (!BN_usub(r, a, b)) { 241 return 0; 242 } 243 r->neg = 0; 244 } 245 246 return 1; 247 } 248 249 int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { 250 int max, min, dif; 251 register BN_ULONG t1, t2, *ap, *bp, *rp; 252 int i, carry; 253 254 max = a->top; 255 min = b->top; 256 dif = max - min; 257 258 if (dif < 0) // hmm... should not be happening 259 { 260 OPENSSL_PUT_ERROR(BN, BN_R_ARG2_LT_ARG3); 261 return 0; 262 } 263 264 if (!bn_wexpand(r, max)) { 265 return 0; 266 } 267 268 ap = a->d; 269 bp = b->d; 270 rp = r->d; 271 272 carry = 0; 273 for (i = min; i != 0; i--) { 274 t1 = *(ap++); 275 t2 = *(bp++); 276 if (carry) { 277 carry = (t1 <= t2); 278 t1 -= t2 + 1; 279 } else { 280 carry = (t1 < t2); 281 t1 -= t2; 282 } 283 *(rp++) = t1; 284 } 285 286 if (carry) // subtracted 287 { 288 if (!dif) { 289 // error: a < b 290 return 0; 291 } 292 293 while (dif) { 294 dif--; 295 t1 = *(ap++); 296 t2 = t1 - 1; 297 *(rp++) = t2; 298 if (t1) { 299 break; 300 } 301 } 302 } 303 304 if (dif > 0 && rp != ap) { 305 OPENSSL_memcpy(rp, ap, sizeof(*rp) * dif); 306 } 307 308 r->top = max; 309 r->neg = 0; 310 bn_correct_top(r); 311 312 return 1; 313 } 314 315 int BN_sub_word(BIGNUM *a, BN_ULONG w) { 316 int i; 317 318 // degenerate case: w is zero 319 if (!w) { 320 return 1; 321 } 322 323 // degenerate case: a is zero 324 if (BN_is_zero(a)) { 325 i = BN_set_word(a, w); 326 if (i != 0) { 327 BN_set_negative(a, 1); 328 } 329 return i; 330 } 331 332 // handle 'a' when negative 333 if (a->neg) { 334 a->neg = 0; 335 i = BN_add_word(a, w); 336 a->neg = 1; 337 return i; 338 } 339 340 if ((a->top == 1) && (a->d[0] < w)) { 341 a->d[0] = w - a->d[0]; 342 a->neg = 1; 343 return 1; 344 } 345 346 i = 0; 347 for (;;) { 348 if (a->d[i] >= w) { 349 a->d[i] -= w; 350 break; 351 } else { 352 a->d[i] -= w; 353 i++; 354 w = 1; 355 } 356 } 357 358 if ((a->d[i] == 0) && (i == (a->top - 1))) { 359 a->top--; 360 } 361 362 return 1; 363 } 364