05ede3b25029d9bc60d9437cfaaaf3da580d3120
[openssl.git] / crypto / bn / bn_asm.c
1 /* crypto/bn/bn_asm.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 #ifdef BN_LLONG 
64
65 BN_ULONG bn_mul_add_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
66         {
67         BN_ULONG c1=0;
68
69         bn_check_num(num);
70         if (num <= 0) return(c1);
71
72         for (;;)
73                 {
74                 mul_add(rp[0],ap[0],w,c1);
75                 if (--num == 0) break;
76                 mul_add(rp[1],ap[1],w,c1);
77                 if (--num == 0) break;
78                 mul_add(rp[2],ap[2],w,c1);
79                 if (--num == 0) break;
80                 mul_add(rp[3],ap[3],w,c1);
81                 if (--num == 0) break;
82                 ap+=4;
83                 rp+=4;
84                 }
85         
86         return(c1);
87         } 
88
89 BN_ULONG bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
90         {
91         BN_ULONG c1=0;
92
93         bn_check_num(num);
94         if (num <= 0) return(c1);
95
96         for (;;)
97                 {
98                 mul(rp[0],ap[0],w,c1);
99                 if (--num == 0) break;
100                 mul(rp[1],ap[1],w,c1);
101                 if (--num == 0) break;
102                 mul(rp[2],ap[2],w,c1);
103                 if (--num == 0) break;
104                 mul(rp[3],ap[3],w,c1);
105                 if (--num == 0) break;
106                 ap+=4;
107                 rp+=4;
108                 }
109         return(c1);
110         } 
111
112 void bn_sqr_words(BN_ULONG *r, BN_ULONG *a, int n)
113         {
114         bn_check_num(n);
115         if (n <= 0) return;
116         for (;;)
117                 {
118                 BN_ULLONG t;
119
120                 t=(BN_ULLONG)(a[0])*(a[0]);
121                 r[0]=Lw(t); r[1]=Hw(t);
122                 if (--n == 0) break;
123
124                 t=(BN_ULLONG)(a[1])*(a[1]);
125                 r[2]=Lw(t); r[3]=Hw(t);
126                 if (--n == 0) break;
127
128                 t=(BN_ULLONG)(a[2])*(a[2]);
129                 r[4]=Lw(t); r[5]=Hw(t);
130                 if (--n == 0) break;
131
132                 t=(BN_ULLONG)(a[3])*(a[3]);
133                 r[6]=Lw(t); r[7]=Hw(t);
134                 if (--n == 0) break;
135
136                 a+=4;
137                 r+=8;
138                 }
139         }
140
141 #else
142
143 BN_ULONG bn_mul_add_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
144         {
145         BN_ULONG c=0;
146         BN_ULONG bl,bh;
147
148         bn_check_num(num);
149         if (num <= 0) return((BN_ULONG)0);
150
151         bl=LBITS(w);
152         bh=HBITS(w);
153
154         for (;;)
155                 {
156                 mul_add(rp[0],ap[0],bl,bh,c);
157                 if (--num == 0) break;
158                 mul_add(rp[1],ap[1],bl,bh,c);
159                 if (--num == 0) break;
160                 mul_add(rp[2],ap[2],bl,bh,c);
161                 if (--num == 0) break;
162                 mul_add(rp[3],ap[3],bl,bh,c);
163                 if (--num == 0) break;
164                 ap+=4;
165                 rp+=4;
166                 }
167         return(c);
168         } 
169
170 BN_ULONG bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
171         {
172         BN_ULONG carry=0;
173         BN_ULONG bl,bh;
174
175         bn_check_num(num);
176         if (num <= 0) return((BN_ULONG)0);
177
178         bl=LBITS(w);
179         bh=HBITS(w);
180
181         for (;;)
182                 {
183                 mul(rp[0],ap[0],bl,bh,carry);
184                 if (--num == 0) break;
185                 mul(rp[1],ap[1],bl,bh,carry);
186                 if (--num == 0) break;
187                 mul(rp[2],ap[2],bl,bh,carry);
188                 if (--num == 0) break;
189                 mul(rp[3],ap[3],bl,bh,carry);
190                 if (--num == 0) break;
191                 ap+=4;
192                 rp+=4;
193                 }
194         return(carry);
195         } 
196
197 void bn_sqr_words(BN_ULONG *r, BN_ULONG *a, int n)
198         {
199         bn_check_num(n);
200         if (n <= 0) return;
201         for (;;)
202                 {
203                 sqr64(r[0],r[1],a[0]);
204                 if (--n == 0) break;
205
206                 sqr64(r[2],r[3],a[1]);
207                 if (--n == 0) break;
208
209                 sqr64(r[4],r[5],a[2]);
210                 if (--n == 0) break;
211
212                 sqr64(r[6],r[7],a[3]);
213                 if (--n == 0) break;
214
215                 a+=4;
216                 r+=8;
217                 }
218         }
219
220 #endif
221
222 #if defined(BN_LLONG) && defined(BN_DIV2W)
223
224 BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d)
225         {
226         return((BN_ULONG)(((((BN_ULLONG)h)<<BN_BITS2)|l)/(BN_ULLONG)d));
227         }
228
229 #else
230
231 /* Divide h-l by d and return the result. */
232 /* I need to test this some more :-( */
233 BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d)
234         {
235         BN_ULONG dh,dl,q,ret=0,th,tl,t;
236         int i,count=2;
237
238         if (d == 0) return(BN_MASK2);
239
240         i=BN_num_bits_word(d);
241         if ((i != BN_BITS2) && (h > (BN_ULONG)1<<i))
242                 {
243 #if !defined(NO_STDIO) && !defined(WIN16)
244                 fprintf(stderr,"Division would overflow (%d)\n",i);
245 #endif
246                 abort();
247                 }
248         i=BN_BITS2-i;
249         if (h >= d) h-=d;
250
251         if (i)
252                 {
253                 d<<=i;
254                 h=(h<<i)|(l>>(BN_BITS2-i));
255                 l<<=i;
256                 }
257         dh=(d&BN_MASK2h)>>BN_BITS4;
258         dl=(d&BN_MASK2l);
259         for (;;)
260                 {
261                 if ((h>>BN_BITS4) == dh)
262                         q=BN_MASK2l;
263                 else
264                         q=h/dh;
265
266                 for (;;)
267                         {
268                         t=(h-q*dh);
269                         if ((t&BN_MASK2h) ||
270                                 ((dl*q) <= (
271                                         (t<<BN_BITS4)+
272                                         ((l&BN_MASK2h)>>BN_BITS4))))
273                                 break;
274                         q--;
275                         }
276                 th=q*dh;
277                 tl=q*dl;
278                 t=(tl>>BN_BITS4);
279                 tl=(tl<<BN_BITS4)&BN_MASK2h;
280                 th+=t;
281
282                 if (l < tl) th++;
283                 l-=tl;
284                 if (h < th)
285                         {
286                         h+=d;
287                         q--;
288                         }
289                 h-=th;
290
291                 if (--count == 0) break;
292
293                 ret=q<<BN_BITS4;
294                 h=((h<<BN_BITS4)|(l>>BN_BITS4))&BN_MASK2;
295                 l=(l&BN_MASK2l)<<BN_BITS4;
296                 }
297         ret|=q;
298         return(ret);
299         }
300 #endif
301
302 #ifdef BN_LLONG
303 BN_ULONG bn_add_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
304         {
305         BN_ULLONG ll=0;
306
307         bn_check_num(n);
308         if (n <= 0) return((BN_ULONG)0);
309
310         for (;;)
311                 {
312                 ll+=(BN_ULLONG)a[0]+b[0];
313                 r[0]=(BN_ULONG)ll&BN_MASK2;
314                 ll>>=BN_BITS2;
315                 if (--n <= 0) break;
316
317                 ll+=(BN_ULLONG)a[1]+b[1];
318                 r[1]=(BN_ULONG)ll&BN_MASK2;
319                 ll>>=BN_BITS2;
320                 if (--n <= 0) break;
321
322                 ll+=(BN_ULLONG)a[2]+b[2];
323                 r[2]=(BN_ULONG)ll&BN_MASK2;
324                 ll>>=BN_BITS2;
325                 if (--n <= 0) break;
326
327                 ll+=(BN_ULLONG)a[3]+b[3];
328                 r[3]=(BN_ULONG)ll&BN_MASK2;
329                 ll>>=BN_BITS2;
330                 if (--n <= 0) break;
331
332                 a+=4;
333                 b+=4;
334                 r+=4;
335                 }
336         return((BN_ULONG)ll);
337         }
338 #else
339 BN_ULONG bn_add_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
340         {
341         BN_ULONG c,l,t;
342
343         bn_check_num(n);
344         if (n <= 0) return((BN_ULONG)0);
345
346         c=0;
347         for (;;)
348                 {
349                 t=a[0];
350                 t=(t+c)&BN_MASK2;
351                 c=(t < c);
352                 l=(t+b[0])&BN_MASK2;
353                 c+=(l < t);
354                 r[0]=l;
355                 if (--n <= 0) break;
356
357                 t=a[1];
358                 t=(t+c)&BN_MASK2;
359                 c=(t < c);
360                 l=(t+b[1])&BN_MASK2;
361                 c+=(l < t);
362                 r[1]=l;
363                 if (--n <= 0) break;
364
365                 t=a[2];
366                 t=(t+c)&BN_MASK2;
367                 c=(t < c);
368                 l=(t+b[2])&BN_MASK2;
369                 c+=(l < t);
370                 r[2]=l;
371                 if (--n <= 0) break;
372
373                 t=a[3];
374                 t=(t+c)&BN_MASK2;
375                 c=(t < c);
376                 l=(t+b[3])&BN_MASK2;
377                 c+=(l < t);
378                 r[3]=l;
379                 if (--n <= 0) break;
380
381                 a+=4;
382                 b+=4;
383                 r+=4;
384                 }
385         return((BN_ULONG)c);
386         }
387 #endif
388
389 BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
390         {
391         BN_ULONG t1,t2;
392         int c=0;
393
394         bn_check_num(n);
395         if (n <= 0) return((BN_ULONG)0);
396
397         for (;;)
398                 {
399                 t1=a[0]; t2=b[0];
400                 r[0]=(t1-t2-c)&BN_MASK2;
401                 if (t1 != t2) c=(t1 < t2);
402                 if (--n <= 0) break;
403
404                 t1=a[1]; t2=b[1];
405                 r[1]=(t1-t2-c)&BN_MASK2;
406                 if (t1 != t2) c=(t1 < t2);
407                 if (--n <= 0) break;
408
409                 t1=a[2]; t2=b[2];
410                 r[2]=(t1-t2-c)&BN_MASK2;
411                 if (t1 != t2) c=(t1 < t2);
412                 if (--n <= 0) break;
413
414                 t1=a[3]; t2=b[3];
415                 r[3]=(t1-t2-c)&BN_MASK2;
416                 if (t1 != t2) c=(t1 < t2);
417                 if (--n <= 0) break;
418
419                 a+=4;
420                 b+=4;
421                 r+=4;
422                 }
423         return(c);
424         }
425
426 #ifdef BN_MUL_COMBA
427
428 #undef bn_mul_comba8
429 #undef bn_mul_comba4
430 #undef bn_sqr_comba8
431 #undef bn_sqr_comba4
432
433 #ifdef BN_LLONG
434 #define mul_add_c(a,b,c0,c1,c2) \
435         t=(BN_ULLONG)a*b; \
436         t1=(BN_ULONG)Lw(t); \
437         t2=(BN_ULONG)Hw(t); \
438         c0=(c0+t1)&BN_MASK2; if ((c0) < t1) t2++; \
439         c1=(c1+t2)&BN_MASK2; if ((c1) < t2) c2++;
440
441 #define mul_add_c2(a,b,c0,c1,c2) \
442         t=(BN_ULLONG)a*b; \
443         tt=(t+t)&BN_MASK; \
444         if (tt < t) c2++; \
445         t1=(BN_ULONG)Lw(tt); \
446         t2=(BN_ULONG)Hw(tt); \
447         c0=(c0+t1)&BN_MASK2;  \
448         if ((c0 < t1) && (((++t2)&BN_MASK2) == 0)) c2++; \
449         c1=(c1+t2)&BN_MASK2; if ((c1) < t2) c2++;
450
451 #define sqr_add_c(a,i,c0,c1,c2) \
452         t=(BN_ULLONG)a[i]*a[i]; \
453         t1=(BN_ULONG)Lw(t); \
454         t2=(BN_ULONG)Hw(t); \
455         c0=(c0+t1)&BN_MASK2; if ((c0) < t1) t2++; \
456         c1=(c1+t2)&BN_MASK2; if ((c1) < t2) c2++;
457
458 #define sqr_add_c2(a,i,j,c0,c1,c2) \
459         mul_add_c2((a)[i],(a)[j],c0,c1,c2)
460 #else
461 #define mul_add_c(a,b,c0,c1,c2) \
462         t1=LBITS(a); t2=HBITS(a); \
463         bl=LBITS(b); bh=HBITS(b); \
464         mul64(t1,t2,bl,bh); \
465         c0=(c0+t1)&BN_MASK2; if ((c0) < t1) t2++; \
466         c1=(c1+t2)&BN_MASK2; if ((c1) < t2) c2++;
467
468 #define mul_add_c2(a,b,c0,c1,c2) \
469         t1=LBITS(a); t2=HBITS(a); \
470         bl=LBITS(b); bh=HBITS(b); \
471         mul64(t1,t2,bl,bh); \
472         if (t2 & BN_TBIT) c2++; \
473         t2=(t2+t2)&BN_MASK2; \
474         if (t1 & BN_TBIT) t2++; \
475         t1=(t1+t1)&BN_MASK2; \
476         c0=(c0+t1)&BN_MASK2;  \
477         if ((c0 < t1) && (((++t2)&BN_MASK2) == 0)) c2++; \
478         c1=(c1+t2)&BN_MASK2; if ((c1) < t2) c2++;
479
480 #define sqr_add_c(a,i,c0,c1,c2) \
481         sqr64(t1,t2,(a)[i]); \
482         c0=(c0+t1)&BN_MASK2; if ((c0) < t1) t2++; \
483         c1=(c1+t2)&BN_MASK2; if ((c1) < t2) c2++;
484
485 #define sqr_add_c2(a,i,j,c0,c1,c2) \
486         mul_add_c2((a)[i],(a)[j],c0,c1,c2)
487 #endif
488
489 void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
490         {
491 #ifdef BN_LLONG
492         BN_ULLONG t;
493 #else
494         BN_ULONG bl,bh;
495 #endif
496         BN_ULONG t1,t2;
497         BN_ULONG c1,c2,c3;
498
499         c1=0;
500         c2=0;
501         c3=0;
502         mul_add_c(a[0],b[0],c1,c2,c3);
503         r[0]=c1;
504         c1=0;
505         mul_add_c(a[0],b[1],c2,c3,c1);
506         mul_add_c(a[1],b[0],c2,c3,c1);
507         r[1]=c2;
508         c2=0;
509         mul_add_c(a[2],b[0],c3,c1,c2);
510         mul_add_c(a[1],b[1],c3,c1,c2);
511         mul_add_c(a[0],b[2],c3,c1,c2);
512         r[2]=c3;
513         c3=0;
514         mul_add_c(a[0],b[3],c1,c2,c3);
515         mul_add_c(a[1],b[2],c1,c2,c3);
516         mul_add_c(a[2],b[1],c1,c2,c3);
517         mul_add_c(a[3],b[0],c1,c2,c3);
518         r[3]=c1;
519         c1=0;
520         mul_add_c(a[4],b[0],c2,c3,c1);
521         mul_add_c(a[3],b[1],c2,c3,c1);
522         mul_add_c(a[2],b[2],c2,c3,c1);
523         mul_add_c(a[1],b[3],c2,c3,c1);
524         mul_add_c(a[0],b[4],c2,c3,c1);
525         r[4]=c2;
526         c2=0;
527         mul_add_c(a[0],b[5],c3,c1,c2);
528         mul_add_c(a[1],b[4],c3,c1,c2);
529         mul_add_c(a[2],b[3],c3,c1,c2);
530         mul_add_c(a[3],b[2],c3,c1,c2);
531         mul_add_c(a[4],b[1],c3,c1,c2);
532         mul_add_c(a[5],b[0],c3,c1,c2);
533         r[5]=c3;
534         c3=0;
535         mul_add_c(a[6],b[0],c1,c2,c3);
536         mul_add_c(a[5],b[1],c1,c2,c3);
537         mul_add_c(a[4],b[2],c1,c2,c3);
538         mul_add_c(a[3],b[3],c1,c2,c3);
539         mul_add_c(a[2],b[4],c1,c2,c3);
540         mul_add_c(a[1],b[5],c1,c2,c3);
541         mul_add_c(a[0],b[6],c1,c2,c3);
542         r[6]=c1;
543         c1=0;
544         mul_add_c(a[0],b[7],c2,c3,c1);
545         mul_add_c(a[1],b[6],c2,c3,c1);
546         mul_add_c(a[2],b[5],c2,c3,c1);
547         mul_add_c(a[3],b[4],c2,c3,c1);
548         mul_add_c(a[4],b[3],c2,c3,c1);
549         mul_add_c(a[5],b[2],c2,c3,c1);
550         mul_add_c(a[6],b[1],c2,c3,c1);
551         mul_add_c(a[7],b[0],c2,c3,c1);
552         r[7]=c2;
553         c2=0;
554         mul_add_c(a[7],b[1],c3,c1,c2);
555         mul_add_c(a[6],b[2],c3,c1,c2);
556         mul_add_c(a[5],b[3],c3,c1,c2);
557         mul_add_c(a[4],b[4],c3,c1,c2);
558         mul_add_c(a[3],b[5],c3,c1,c2);
559         mul_add_c(a[2],b[6],c3,c1,c2);
560         mul_add_c(a[1],b[7],c3,c1,c2);
561         r[8]=c3;
562         c3=0;
563         mul_add_c(a[2],b[7],c1,c2,c3);
564         mul_add_c(a[3],b[6],c1,c2,c3);
565         mul_add_c(a[4],b[5],c1,c2,c3);
566         mul_add_c(a[5],b[4],c1,c2,c3);
567         mul_add_c(a[6],b[3],c1,c2,c3);
568         mul_add_c(a[7],b[2],c1,c2,c3);
569         r[9]=c1;
570         c1=0;
571         mul_add_c(a[7],b[3],c2,c3,c1);
572         mul_add_c(a[6],b[4],c2,c3,c1);
573         mul_add_c(a[5],b[5],c2,c3,c1);
574         mul_add_c(a[4],b[6],c2,c3,c1);
575         mul_add_c(a[3],b[7],c2,c3,c1);
576         r[10]=c2;
577         c2=0;
578         mul_add_c(a[4],b[7],c3,c1,c2);
579         mul_add_c(a[5],b[6],c3,c1,c2);
580         mul_add_c(a[6],b[5],c3,c1,c2);
581         mul_add_c(a[7],b[4],c3,c1,c2);
582         r[11]=c3;
583         c3=0;
584         mul_add_c(a[7],b[5],c1,c2,c3);
585         mul_add_c(a[6],b[6],c1,c2,c3);
586         mul_add_c(a[5],b[7],c1,c2,c3);
587         r[12]=c1;
588         c1=0;
589         mul_add_c(a[6],b[7],c2,c3,c1);
590         mul_add_c(a[7],b[6],c2,c3,c1);
591         r[13]=c2;
592         c2=0;
593         mul_add_c(a[7],b[7],c3,c1,c2);
594         r[14]=c3;
595         r[15]=c1;
596         }
597
598 void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
599         {
600 #ifdef BN_LLONG
601         BN_ULLONG t;
602 #else
603         BN_ULONG bl,bh;
604 #endif
605         BN_ULONG t1,t2;
606         BN_ULONG c1,c2,c3;
607
608         c1=0;
609         c2=0;
610         c3=0;
611         mul_add_c(a[0],b[0],c1,c2,c3);
612         r[0]=c1;
613         c1=0;
614         mul_add_c(a[0],b[1],c2,c3,c1);
615         mul_add_c(a[1],b[0],c2,c3,c1);
616         r[1]=c2;
617         c2=0;
618         mul_add_c(a[2],b[0],c3,c1,c2);
619         mul_add_c(a[1],b[1],c3,c1,c2);
620         mul_add_c(a[0],b[2],c3,c1,c2);
621         r[2]=c3;
622         c3=0;
623         mul_add_c(a[0],b[3],c1,c2,c3);
624         mul_add_c(a[1],b[2],c1,c2,c3);
625         mul_add_c(a[2],b[1],c1,c2,c3);
626         mul_add_c(a[3],b[0],c1,c2,c3);
627         r[3]=c1;
628         c1=0;
629         mul_add_c(a[3],b[1],c2,c3,c1);
630         mul_add_c(a[2],b[2],c2,c3,c1);
631         mul_add_c(a[1],b[3],c2,c3,c1);
632         r[4]=c2;
633         c2=0;
634         mul_add_c(a[2],b[3],c3,c1,c2);
635         mul_add_c(a[3],b[2],c3,c1,c2);
636         r[5]=c3;
637         c3=0;
638         mul_add_c(a[3],b[3],c1,c2,c3);
639         r[6]=c1;
640         r[7]=c2;
641         }
642
643 void bn_sqr_comba8(BN_ULONG *r, BN_ULONG *a)
644         {
645 #ifdef BN_LLONG
646         BN_ULLONG t,tt;
647 #else
648         BN_ULONG bl,bh;
649 #endif
650         BN_ULONG t1,t2;
651         BN_ULONG c1,c2,c3;
652
653         c1=0;
654         c2=0;
655         c3=0;
656         sqr_add_c(a,0,c1,c2,c3);
657         r[0]=c1;
658         c1=0;
659         sqr_add_c2(a,1,0,c2,c3,c1);
660         r[1]=c2;
661         c2=0;
662         sqr_add_c(a,1,c3,c1,c2);
663         sqr_add_c2(a,2,0,c3,c1,c2);
664         r[2]=c3;
665         c3=0;
666         sqr_add_c2(a,3,0,c1,c2,c3);
667         sqr_add_c2(a,2,1,c1,c2,c3);
668         r[3]=c1;
669         c1=0;
670         sqr_add_c(a,2,c2,c3,c1);
671         sqr_add_c2(a,3,1,c2,c3,c1);
672         sqr_add_c2(a,4,0,c2,c3,c1);
673         r[4]=c2;
674         c2=0;
675         sqr_add_c2(a,5,0,c3,c1,c2);
676         sqr_add_c2(a,4,1,c3,c1,c2);
677         sqr_add_c2(a,3,2,c3,c1,c2);
678         r[5]=c3;
679         c3=0;
680         sqr_add_c(a,3,c1,c2,c3);
681         sqr_add_c2(a,4,2,c1,c2,c3);
682         sqr_add_c2(a,5,1,c1,c2,c3);
683         sqr_add_c2(a,6,0,c1,c2,c3);
684         r[6]=c1;
685         c1=0;
686         sqr_add_c2(a,7,0,c2,c3,c1);
687         sqr_add_c2(a,6,1,c2,c3,c1);
688         sqr_add_c2(a,5,2,c2,c3,c1);
689         sqr_add_c2(a,4,3,c2,c3,c1);
690         r[7]=c2;
691         c2=0;
692         sqr_add_c(a,4,c3,c1,c2);
693         sqr_add_c2(a,5,3,c3,c1,c2);
694         sqr_add_c2(a,6,2,c3,c1,c2);
695         sqr_add_c2(a,7,1,c3,c1,c2);
696         r[8]=c3;
697         c3=0;
698         sqr_add_c2(a,7,2,c1,c2,c3);
699         sqr_add_c2(a,6,3,c1,c2,c3);
700         sqr_add_c2(a,5,4,c1,c2,c3);
701         r[9]=c1;
702         c1=0;
703         sqr_add_c(a,5,c2,c3,c1);
704         sqr_add_c2(a,6,4,c2,c3,c1);
705         sqr_add_c2(a,7,3,c2,c3,c1);
706         r[10]=c2;
707         c2=0;
708         sqr_add_c2(a,7,4,c3,c1,c2);
709         sqr_add_c2(a,6,5,c3,c1,c2);
710         r[11]=c3;
711         c3=0;
712         sqr_add_c(a,6,c1,c2,c3);
713         sqr_add_c2(a,7,5,c1,c2,c3);
714         r[12]=c1;
715         c1=0;
716         sqr_add_c2(a,7,6,c2,c3,c1);
717         r[13]=c2;
718         c2=0;
719         sqr_add_c(a,7,c3,c1,c2);
720         r[14]=c3;
721         r[15]=c1;
722         }
723
724 void bn_sqr_comba4(BN_ULONG *r, BN_ULONG *a)
725         {
726 #ifdef BN_LLONG
727         BN_ULLONG t,tt;
728 #else
729         BN_ULONG bl,bh;
730 #endif
731         BN_ULONG t1,t2;
732         BN_ULONG c1,c2,c3;
733
734         c1=0;
735         c2=0;
736         c3=0;
737         sqr_add_c(a,0,c1,c2,c3);
738         r[0]=c1;
739         c1=0;
740         sqr_add_c2(a,1,0,c2,c3,c1);
741         r[1]=c2;
742         c2=0;
743         sqr_add_c(a,1,c3,c1,c2);
744         sqr_add_c2(a,2,0,c3,c1,c2);
745         r[2]=c3;
746         c3=0;
747         sqr_add_c2(a,3,0,c1,c2,c3);
748         sqr_add_c2(a,2,1,c1,c2,c3);
749         r[3]=c1;
750         c1=0;
751         sqr_add_c(a,2,c2,c3,c1);
752         sqr_add_c2(a,3,1,c2,c3,c1);
753         r[4]=c2;
754         c2=0;
755         sqr_add_c2(a,3,2,c3,c1,c2);
756         r[5]=c3;
757         c3=0;
758         sqr_add_c(a,3,c1,c2,c3);
759         r[6]=c1;
760         r[7]=c2;
761         }
762 #else
763
764 /* hmm... is it faster just to do a multiply? */
765 #undef bn_sqr_comba4
766 void bn_sqr_comba4(BN_ULONG *r, BN_ULONG *a)
767         {
768         BN_ULONG t[8];
769         bn_sqr_normal(r,a,4,t);
770         }
771
772 #undef bn_sqr_comba8
773 void bn_sqr_comba8(BN_ULONG *r, BN_ULONG *a)
774         {
775         BN_ULONG t[16];
776         bn_sqr_normal(r,a,8,t);
777         }
778
779 void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
780         {
781         r[4]=bn_mul_words(    &(r[0]),a,4,b[0]);
782         r[5]=bn_mul_add_words(&(r[1]),a,4,b[1]);
783         r[6]=bn_mul_add_words(&(r[2]),a,4,b[2]);
784         r[7]=bn_mul_add_words(&(r[3]),a,4,b[3]);
785         }
786
787 void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
788         {
789         r[ 8]=bn_mul_words(    &(r[0]),a,8,b[0]);
790         r[ 9]=bn_mul_add_words(&(r[1]),a,8,b[1]);
791         r[10]=bn_mul_add_words(&(r[2]),a,8,b[2]);
792         r[11]=bn_mul_add_words(&(r[3]),a,8,b[3]);
793         r[12]=bn_mul_add_words(&(r[4]),a,8,b[4]);
794         r[13]=bn_mul_add_words(&(r[5]),a,8,b[5]);
795         r[14]=bn_mul_add_words(&(r[6]),a,8,b[6]);
796         r[15]=bn_mul_add_words(&(r[7]),a,8,b[7]);
797         }
798
799 #endif /* BN_COMBA */