]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/openssl/crypto/bn/bn_sqr.c
Merge OpenSSL 1.0.2q.
[FreeBSD/FreeBSD.git] / crypto / openssl / crypto / bn / bn_sqr.c
1 /* crypto/bn/bn_sqr.c */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3  * All rights reserved.
4  *
5  * This package is an SSL implementation written
6  * by Eric Young (eay@cryptsoft.com).
7  * The implementation was written so as to conform with Netscapes SSL.
8  *
9  * This library is free for commercial and non-commercial use as long as
10  * the following conditions are aheared to.  The following conditions
11  * apply to all code found in this distribution, be it the RC4, RSA,
12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13  * included with this distribution is covered by the same copyright terms
14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15  *
16  * Copyright remains Eric Young's, and as such any Copyright notices in
17  * the code are not to be removed.
18  * If this package is used in a product, Eric Young should be given attribution
19  * as the author of the parts of the library used.
20  * This can be in the form of a textual message at program startup or
21  * in documentation (online or textual) provided with the package.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. All advertising materials mentioning features or use of this software
32  *    must display the following acknowledgement:
33  *    "This product includes cryptographic software written by
34  *     Eric Young (eay@cryptsoft.com)"
35  *    The word 'cryptographic' can be left out if the rouines from the library
36  *    being used are not cryptographic related :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40  *
41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  *
53  * The licence and distribution terms for any publically available version or
54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55  * copied and put under another distribution licence
56  * [including the GNU Public Licence.]
57  */
58
59 #include <stdio.h>
60 #include "cryptlib.h"
61 #include "bn_lcl.h"
62
63 /* r must not be a */
64 /*
65  * I've just gone over this and it is now %20 faster on x86 - eay - 27 Jun 96
66  */
67 int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
68 {
69     int ret = bn_sqr_fixed_top(r, a, ctx);
70
71     bn_correct_top(r);
72     bn_check_top(r);
73
74     return ret;
75 }
76
77 int bn_sqr_fixed_top(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
78 {
79     int max, al;
80     int ret = 0;
81     BIGNUM *tmp, *rr;
82
83 #ifdef BN_COUNT
84     fprintf(stderr, "BN_sqr %d * %d\n", a->top, a->top);
85 #endif
86     bn_check_top(a);
87
88     al = a->top;
89     if (al <= 0) {
90         r->top = 0;
91         r->neg = 0;
92         return 1;
93     }
94
95     BN_CTX_start(ctx);
96     rr = (a != r) ? r : BN_CTX_get(ctx);
97     tmp = BN_CTX_get(ctx);
98     if (!rr || !tmp)
99         goto err;
100
101     max = 2 * al;               /* Non-zero (from above) */
102     if (bn_wexpand(rr, max) == NULL)
103         goto err;
104
105     if (al == 4) {
106 #ifndef BN_SQR_COMBA
107         BN_ULONG t[8];
108         bn_sqr_normal(rr->d, a->d, 4, t);
109 #else
110         bn_sqr_comba4(rr->d, a->d);
111 #endif
112     } else if (al == 8) {
113 #ifndef BN_SQR_COMBA
114         BN_ULONG t[16];
115         bn_sqr_normal(rr->d, a->d, 8, t);
116 #else
117         bn_sqr_comba8(rr->d, a->d);
118 #endif
119     } else {
120 #if defined(BN_RECURSION)
121         if (al < BN_SQR_RECURSIVE_SIZE_NORMAL) {
122             BN_ULONG t[BN_SQR_RECURSIVE_SIZE_NORMAL * 2];
123             bn_sqr_normal(rr->d, a->d, al, t);
124         } else {
125             int j, k;
126
127             j = BN_num_bits_word((BN_ULONG)al);
128             j = 1 << (j - 1);
129             k = j + j;
130             if (al == j) {
131                 if (bn_wexpand(tmp, k * 2) == NULL)
132                     goto err;
133                 bn_sqr_recursive(rr->d, a->d, al, tmp->d);
134             } else {
135                 if (bn_wexpand(tmp, max) == NULL)
136                     goto err;
137                 bn_sqr_normal(rr->d, a->d, al, tmp->d);
138             }
139         }
140 #else
141         if (bn_wexpand(tmp, max) == NULL)
142             goto err;
143         bn_sqr_normal(rr->d, a->d, al, tmp->d);
144 #endif
145     }
146
147     rr->neg = 0;
148     rr->top = max;
149     rr->flags |= BN_FLG_FIXED_TOP;
150     if (r != rr && BN_copy(r, rr) == NULL)
151         goto err;
152
153     ret = 1;
154  err:
155     bn_check_top(rr);
156     bn_check_top(tmp);
157     BN_CTX_end(ctx);
158     return (ret);
159 }
160
161 /* tmp must have 2*n words */
162 void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, int n, BN_ULONG *tmp)
163 {
164     int i, j, max;
165     const BN_ULONG *ap;
166     BN_ULONG *rp;
167
168     max = n * 2;
169     ap = a;
170     rp = r;
171     rp[0] = rp[max - 1] = 0;
172     rp++;
173     j = n;
174
175     if (--j > 0) {
176         ap++;
177         rp[j] = bn_mul_words(rp, ap, j, ap[-1]);
178         rp += 2;
179     }
180
181     for (i = n - 2; i > 0; i--) {
182         j--;
183         ap++;
184         rp[j] = bn_mul_add_words(rp, ap, j, ap[-1]);
185         rp += 2;
186     }
187
188     bn_add_words(r, r, r, max);
189
190     /* There will not be a carry */
191
192     bn_sqr_words(tmp, a, n);
193
194     bn_add_words(r, r, tmp, max);
195 }
196
197 #ifdef BN_RECURSION
198 /*-
199  * r is 2*n words in size,
200  * a and b are both n words in size.    (There's not actually a 'b' here ...)
201  * n must be a power of 2.
202  * We multiply and return the result.
203  * t must be 2*n words in size
204  * We calculate
205  * a[0]*b[0]
206  * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
207  * a[1]*b[1]
208  */
209 void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t)
210 {
211     int n = n2 / 2;
212     int zero, c1;
213     BN_ULONG ln, lo, *p;
214
215 # ifdef BN_COUNT
216     fprintf(stderr, " bn_sqr_recursive %d * %d\n", n2, n2);
217 # endif
218     if (n2 == 4) {
219 # ifndef BN_SQR_COMBA
220         bn_sqr_normal(r, a, 4, t);
221 # else
222         bn_sqr_comba4(r, a);
223 # endif
224         return;
225     } else if (n2 == 8) {
226 # ifndef BN_SQR_COMBA
227         bn_sqr_normal(r, a, 8, t);
228 # else
229         bn_sqr_comba8(r, a);
230 # endif
231         return;
232     }
233     if (n2 < BN_SQR_RECURSIVE_SIZE_NORMAL) {
234         bn_sqr_normal(r, a, n2, t);
235         return;
236     }
237     /* r=(a[0]-a[1])*(a[1]-a[0]) */
238     c1 = bn_cmp_words(a, &(a[n]), n);
239     zero = 0;
240     if (c1 > 0)
241         bn_sub_words(t, a, &(a[n]), n);
242     else if (c1 < 0)
243         bn_sub_words(t, &(a[n]), a, n);
244     else
245         zero = 1;
246
247     /* The result will always be negative unless it is zero */
248     p = &(t[n2 * 2]);
249
250     if (!zero)
251         bn_sqr_recursive(&(t[n2]), t, n, p);
252     else
253         memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG));
254     bn_sqr_recursive(r, a, n, p);
255     bn_sqr_recursive(&(r[n2]), &(a[n]), n, p);
256
257     /*-
258      * t[32] holds (a[0]-a[1])*(a[1]-a[0]), it is negative or zero
259      * r[10] holds (a[0]*b[0])
260      * r[32] holds (b[1]*b[1])
261      */
262
263     c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
264
265     /* t[32] is negative */
266     c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
267
268     /*-
269      * t[32] holds (a[0]-a[1])*(a[1]-a[0])+(a[0]*a[0])+(a[1]*a[1])
270      * r[10] holds (a[0]*a[0])
271      * r[32] holds (a[1]*a[1])
272      * c1 holds the carry bits
273      */
274     c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
275     if (c1) {
276         p = &(r[n + n2]);
277         lo = *p;
278         ln = (lo + c1) & BN_MASK2;
279         *p = ln;
280
281         /*
282          * The overflow will stop before we over write words we should not
283          * overwrite
284          */
285         if (ln < (BN_ULONG)c1) {
286             do {
287                 p++;
288                 lo = *p;
289                 ln = (lo + 1) & BN_MASK2;
290                 *p = ln;
291             } while (ln == 0);
292         }
293     }
294 }
295 #endif