1 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young (eay@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@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@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@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 
BN_add(BIGNUM * r,const BIGNUM * a,const BIGNUM * b)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 
BN_uadd(BIGNUM * r,const BIGNUM * a,const BIGNUM * b)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 
BN_add_word(BIGNUM * a,BN_ULONG w)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 
BN_sub(BIGNUM * r,const BIGNUM * a,const BIGNUM * b)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 
BN_usub(BIGNUM * r,const BIGNUM * a,const BIGNUM * b)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 
BN_sub_word(BIGNUM * a,BN_ULONG w)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