]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/openssl/crypto/bn/asm/x86_64-gcc.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / crypto / openssl / crypto / bn / asm / x86_64-gcc.c
1 #include "../bn_lcl.h"
2 #ifdef __SUNPRO_C
3 # include "../bn_asm.c" /* kind of dirty hack for Sun Studio */
4 #else
5 /*
6  * x86_64 BIGNUM accelerator version 0.1, December 2002.
7  *
8  * Implemented by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
9  * project.
10  *
11  * Rights for redistribution and usage in source and binary forms are
12  * granted according to the OpenSSL license. Warranty of any kind is
13  * disclaimed.
14  *
15  * Q. Version 0.1? It doesn't sound like Andy, he used to assign real
16  *    versions, like 1.0...
17  * A. Well, that's because this code is basically a quick-n-dirty
18  *    proof-of-concept hack. As you can see it's implemented with
19  *    inline assembler, which means that you're bound to GCC and that
20  *    there might be enough room for further improvement.
21  *
22  * Q. Why inline assembler?
23  * A. x86_64 features own ABI which I'm not familiar with. This is
24  *    why I decided to let the compiler take care of subroutine
25  *    prologue/epilogue as well as register allocation. For reference.
26  *    Win64 implements different ABI for AMD64, different from Linux.
27  *
28  * Q. How much faster does it get?
29  * A. 'apps/openssl speed rsa dsa' output with no-asm:
30  *
31  *                        sign    verify    sign/s verify/s
32  *      rsa  512 bits   0.0006s   0.0001s   1683.8  18456.2
33  *      rsa 1024 bits   0.0028s   0.0002s    356.0   6407.0
34  *      rsa 2048 bits   0.0172s   0.0005s     58.0   1957.8
35  *      rsa 4096 bits   0.1155s   0.0018s      8.7    555.6
36  *                        sign    verify    sign/s verify/s
37  *      dsa  512 bits   0.0005s   0.0006s   2100.8   1768.3
38  *      dsa 1024 bits   0.0014s   0.0018s    692.3    559.2
39  *      dsa 2048 bits   0.0049s   0.0061s    204.7    165.0
40  *
41  *    'apps/openssl speed rsa dsa' output with this module:
42  *
43  *                        sign    verify    sign/s verify/s
44  *      rsa  512 bits   0.0004s   0.0000s   2767.1  33297.9
45  *      rsa 1024 bits   0.0012s   0.0001s    867.4  14674.7
46  *      rsa 2048 bits   0.0061s   0.0002s    164.0   5270.0
47  *      rsa 4096 bits   0.0384s   0.0006s     26.1   1650.8
48  *                        sign    verify    sign/s verify/s
49  *      dsa  512 bits   0.0002s   0.0003s   4442.2   3786.3
50  *      dsa 1024 bits   0.0005s   0.0007s   1835.1   1497.4
51  *      dsa 2048 bits   0.0016s   0.0020s    620.4    504.6
52  *
53  *    For the reference. IA-32 assembler implementation performs
54  *    very much like 64-bit code compiled with no-asm on the same
55  *    machine.
56  */
57
58 #define BN_ULONG unsigned long
59
60 #undef mul
61 #undef mul_add
62 #undef sqr
63
64 /*
65  * "m"(a), "+m"(r)      is the way to favor DirectPath ยต-code;
66  * "g"(0)               let the compiler to decide where does it
67  *                      want to keep the value of zero;
68  */
69 #define mul_add(r,a,word,carry) do {    \
70         register BN_ULONG high,low;     \
71         asm ("mulq %3"                  \
72                 : "=a"(low),"=d"(high)  \
73                 : "a"(word),"m"(a)      \
74                 : "cc");                \
75         asm ("addq %2,%0; adcq %3,%1"   \
76                 : "+r"(carry),"+d"(high)\
77                 : "a"(low),"g"(0)       \
78                 : "cc");                \
79         asm ("addq %2,%0; adcq %3,%1"   \
80                 : "+m"(r),"+d"(high)    \
81                 : "r"(carry),"g"(0)     \
82                 : "cc");                \
83         carry=high;                     \
84         } while (0)
85
86 #define mul(r,a,word,carry) do {        \
87         register BN_ULONG high,low;     \
88         asm ("mulq %3"                  \
89                 : "=a"(low),"=d"(high)  \
90                 : "a"(word),"g"(a)      \
91                 : "cc");                \
92         asm ("addq %2,%0; adcq %3,%1"   \
93                 : "+r"(carry),"+d"(high)\
94                 : "a"(low),"g"(0)       \
95                 : "cc");                \
96         (r)=carry, carry=high;          \
97         } while (0)
98
99 #define sqr(r0,r1,a)                    \
100         asm ("mulq %2"                  \
101                 : "=a"(r0),"=d"(r1)     \
102                 : "a"(a)                \
103                 : "cc");
104
105 BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w)
106         {
107         BN_ULONG c1=0;
108
109         if (num <= 0) return(c1);
110
111         while (num&~3)
112                 {
113                 mul_add(rp[0],ap[0],w,c1);
114                 mul_add(rp[1],ap[1],w,c1);
115                 mul_add(rp[2],ap[2],w,c1);
116                 mul_add(rp[3],ap[3],w,c1);
117                 ap+=4; rp+=4; num-=4;
118                 }
119         if (num)
120                 {
121                 mul_add(rp[0],ap[0],w,c1); if (--num==0) return c1;
122                 mul_add(rp[1],ap[1],w,c1); if (--num==0) return c1;
123                 mul_add(rp[2],ap[2],w,c1); return c1;
124                 }
125         
126         return(c1);
127         } 
128
129 BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w)
130         {
131         BN_ULONG c1=0;
132
133         if (num <= 0) return(c1);
134
135         while (num&~3)
136                 {
137                 mul(rp[0],ap[0],w,c1);
138                 mul(rp[1],ap[1],w,c1);
139                 mul(rp[2],ap[2],w,c1);
140                 mul(rp[3],ap[3],w,c1);
141                 ap+=4; rp+=4; num-=4;
142                 }
143         if (num)
144                 {
145                 mul(rp[0],ap[0],w,c1); if (--num == 0) return c1;
146                 mul(rp[1],ap[1],w,c1); if (--num == 0) return c1;
147                 mul(rp[2],ap[2],w,c1);
148                 }
149         return(c1);
150         } 
151
152 void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n)
153         {
154         if (n <= 0) return;
155
156         while (n&~3)
157                 {
158                 sqr(r[0],r[1],a[0]);
159                 sqr(r[2],r[3],a[1]);
160                 sqr(r[4],r[5],a[2]);
161                 sqr(r[6],r[7],a[3]);
162                 a+=4; r+=8; n-=4;
163                 }
164         if (n)
165                 {
166                 sqr(r[0],r[1],a[0]); if (--n == 0) return;
167                 sqr(r[2],r[3],a[1]); if (--n == 0) return;
168                 sqr(r[4],r[5],a[2]);
169                 }
170         }
171
172 BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d)
173 {       BN_ULONG ret,waste;
174
175         asm ("divq      %4"
176                 : "=a"(ret),"=d"(waste)
177                 : "a"(l),"d"(h),"g"(d)
178                 : "cc");
179
180         return ret;
181 }
182
183 BN_ULONG bn_add_words (BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int n)
184 { BN_ULONG ret=0,i=0;
185
186         if (n <= 0) return 0;
187
188         asm (
189         "       subq    %2,%2           \n"
190         ".align 16                      \n"
191         "1:     movq    (%4,%2,8),%0    \n"
192         "       adcq    (%5,%2,8),%0    \n"
193         "       movq    %0,(%3,%2,8)    \n"
194         "       leaq    1(%2),%2        \n"
195         "       loop    1b              \n"
196         "       sbbq    %0,%0           \n"
197                 : "=&a"(ret),"+c"(n),"=&r"(i)
198                 : "r"(rp),"r"(ap),"r"(bp)
199                 : "cc"
200         );
201
202   return ret&1;
203 }
204
205 #ifndef SIMICS
206 BN_ULONG bn_sub_words (BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int n)
207 { BN_ULONG ret=0,i=0;
208
209         if (n <= 0) return 0;
210
211         asm (
212         "       subq    %2,%2           \n"
213         ".align 16                      \n"
214         "1:     movq    (%4,%2,8),%0    \n"
215         "       sbbq    (%5,%2,8),%0    \n"
216         "       movq    %0,(%3,%2,8)    \n"
217         "       leaq    1(%2),%2        \n"
218         "       loop    1b              \n"
219         "       sbbq    %0,%0           \n"
220                 : "=&a"(ret),"+c"(n),"=&r"(i)
221                 : "r"(rp),"r"(ap),"r"(bp)
222                 : "cc"
223         );
224
225   return ret&1;
226 }
227 #else
228 /* Simics 1.4<7 has buggy sbbq:-( */
229 #define BN_MASK2 0xffffffffffffffffL
230 BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
231         {
232         BN_ULONG t1,t2;
233         int c=0;
234
235         if (n <= 0) return((BN_ULONG)0);
236
237         for (;;)
238                 {
239                 t1=a[0]; t2=b[0];
240                 r[0]=(t1-t2-c)&BN_MASK2;
241                 if (t1 != t2) c=(t1 < t2);
242                 if (--n <= 0) break;
243
244                 t1=a[1]; t2=b[1];
245                 r[1]=(t1-t2-c)&BN_MASK2;
246                 if (t1 != t2) c=(t1 < t2);
247                 if (--n <= 0) break;
248
249                 t1=a[2]; t2=b[2];
250                 r[2]=(t1-t2-c)&BN_MASK2;
251                 if (t1 != t2) c=(t1 < t2);
252                 if (--n <= 0) break;
253
254                 t1=a[3]; t2=b[3];
255                 r[3]=(t1-t2-c)&BN_MASK2;
256                 if (t1 != t2) c=(t1 < t2);
257                 if (--n <= 0) break;
258
259                 a+=4;
260                 b+=4;
261                 r+=4;
262                 }
263         return(c);
264         }
265 #endif
266
267 /* mul_add_c(a,b,c0,c1,c2)  -- c+=a*b for three word number c=(c2,c1,c0) */
268 /* mul_add_c2(a,b,c0,c1,c2) -- c+=2*a*b for three word number c=(c2,c1,c0) */
269 /* sqr_add_c(a,i,c0,c1,c2)  -- c+=a[i]^2 for three word number c=(c2,c1,c0) */
270 /* sqr_add_c2(a,i,c0,c1,c2) -- c+=2*a[i]*a[j] for three word number c=(c2,c1,c0) */
271
272 #if 0
273 /* original macros are kept for reference purposes */
274 #define mul_add_c(a,b,c0,c1,c2) {       \
275         BN_ULONG ta=(a),tb=(b);         \
276         t1 = ta * tb;                   \
277         t2 = BN_UMULT_HIGH(ta,tb);      \
278         c0 += t1; t2 += (c0<t1)?1:0;    \
279         c1 += t2; c2 += (c1<t2)?1:0;    \
280         }
281
282 #define mul_add_c2(a,b,c0,c1,c2) {      \
283         BN_ULONG ta=(a),tb=(b),t0;      \
284         t1 = BN_UMULT_HIGH(ta,tb);      \
285         t0 = ta * tb;                   \
286         t2 = t1+t1; c2 += (t2<t1)?1:0;  \
287         t1 = t0+t0; t2 += (t1<t0)?1:0;  \
288         c0 += t1; t2 += (c0<t1)?1:0;    \
289         c1 += t2; c2 += (c1<t2)?1:0;    \
290         }
291 #else
292 #define mul_add_c(a,b,c0,c1,c2) do {    \
293         asm ("mulq %3"                  \
294                 : "=a"(t1),"=d"(t2)     \
295                 : "a"(a),"m"(b)         \
296                 : "cc");                \
297         asm ("addq %2,%0; adcq %3,%1"   \
298                 : "+r"(c0),"+d"(t2)     \
299                 : "a"(t1),"g"(0)        \
300                 : "cc");                \
301         asm ("addq %2,%0; adcq %3,%1"   \
302                 : "+r"(c1),"+r"(c2)     \
303                 : "d"(t2),"g"(0)        \
304                 : "cc");                \
305         } while (0)
306
307 #define sqr_add_c(a,i,c0,c1,c2) do {    \
308         asm ("mulq %2"                  \
309                 : "=a"(t1),"=d"(t2)     \
310                 : "a"(a[i])             \
311                 : "cc");                \
312         asm ("addq %2,%0; adcq %3,%1"   \
313                 : "+r"(c0),"+d"(t2)     \
314                 : "a"(t1),"g"(0)        \
315                 : "cc");                \
316         asm ("addq %2,%0; adcq %3,%1"   \
317                 : "+r"(c1),"+r"(c2)     \
318                 : "d"(t2),"g"(0)        \
319                 : "cc");                \
320         } while (0)
321
322 #define mul_add_c2(a,b,c0,c1,c2) do {   \
323         asm ("mulq %3"                  \
324                 : "=a"(t1),"=d"(t2)     \
325                 : "a"(a),"m"(b)         \
326                 : "cc");                \
327         asm ("addq %0,%0; adcq %2,%1"   \
328                 : "+d"(t2),"+r"(c2)     \
329                 : "g"(0)                \
330                 : "cc");                \
331         asm ("addq %0,%0; adcq %2,%1"   \
332                 : "+a"(t1),"+d"(t2)     \
333                 : "g"(0)                \
334                 : "cc");                \
335         asm ("addq %2,%0; adcq %3,%1"   \
336                 : "+r"(c0),"+d"(t2)     \
337                 : "a"(t1),"g"(0)        \
338                 : "cc");                \
339         asm ("addq %2,%0; adcq %3,%1"   \
340                 : "+r"(c1),"+r"(c2)     \
341                 : "d"(t2),"g"(0)        \
342                 : "cc");                \
343         } while (0)
344 #endif
345
346 #define sqr_add_c2(a,i,j,c0,c1,c2)      \
347         mul_add_c2((a)[i],(a)[j],c0,c1,c2)
348
349 void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
350         {
351         BN_ULONG t1,t2;
352         BN_ULONG c1,c2,c3;
353
354         c1=0;
355         c2=0;
356         c3=0;
357         mul_add_c(a[0],b[0],c1,c2,c3);
358         r[0]=c1;
359         c1=0;
360         mul_add_c(a[0],b[1],c2,c3,c1);
361         mul_add_c(a[1],b[0],c2,c3,c1);
362         r[1]=c2;
363         c2=0;
364         mul_add_c(a[2],b[0],c3,c1,c2);
365         mul_add_c(a[1],b[1],c3,c1,c2);
366         mul_add_c(a[0],b[2],c3,c1,c2);
367         r[2]=c3;
368         c3=0;
369         mul_add_c(a[0],b[3],c1,c2,c3);
370         mul_add_c(a[1],b[2],c1,c2,c3);
371         mul_add_c(a[2],b[1],c1,c2,c3);
372         mul_add_c(a[3],b[0],c1,c2,c3);
373         r[3]=c1;
374         c1=0;
375         mul_add_c(a[4],b[0],c2,c3,c1);
376         mul_add_c(a[3],b[1],c2,c3,c1);
377         mul_add_c(a[2],b[2],c2,c3,c1);
378         mul_add_c(a[1],b[3],c2,c3,c1);
379         mul_add_c(a[0],b[4],c2,c3,c1);
380         r[4]=c2;
381         c2=0;
382         mul_add_c(a[0],b[5],c3,c1,c2);
383         mul_add_c(a[1],b[4],c3,c1,c2);
384         mul_add_c(a[2],b[3],c3,c1,c2);
385         mul_add_c(a[3],b[2],c3,c1,c2);
386         mul_add_c(a[4],b[1],c3,c1,c2);
387         mul_add_c(a[5],b[0],c3,c1,c2);
388         r[5]=c3;
389         c3=0;
390         mul_add_c(a[6],b[0],c1,c2,c3);
391         mul_add_c(a[5],b[1],c1,c2,c3);
392         mul_add_c(a[4],b[2],c1,c2,c3);
393         mul_add_c(a[3],b[3],c1,c2,c3);
394         mul_add_c(a[2],b[4],c1,c2,c3);
395         mul_add_c(a[1],b[5],c1,c2,c3);
396         mul_add_c(a[0],b[6],c1,c2,c3);
397         r[6]=c1;
398         c1=0;
399         mul_add_c(a[0],b[7],c2,c3,c1);
400         mul_add_c(a[1],b[6],c2,c3,c1);
401         mul_add_c(a[2],b[5],c2,c3,c1);
402         mul_add_c(a[3],b[4],c2,c3,c1);
403         mul_add_c(a[4],b[3],c2,c3,c1);
404         mul_add_c(a[5],b[2],c2,c3,c1);
405         mul_add_c(a[6],b[1],c2,c3,c1);
406         mul_add_c(a[7],b[0],c2,c3,c1);
407         r[7]=c2;
408         c2=0;
409         mul_add_c(a[7],b[1],c3,c1,c2);
410         mul_add_c(a[6],b[2],c3,c1,c2);
411         mul_add_c(a[5],b[3],c3,c1,c2);
412         mul_add_c(a[4],b[4],c3,c1,c2);
413         mul_add_c(a[3],b[5],c3,c1,c2);
414         mul_add_c(a[2],b[6],c3,c1,c2);
415         mul_add_c(a[1],b[7],c3,c1,c2);
416         r[8]=c3;
417         c3=0;
418         mul_add_c(a[2],b[7],c1,c2,c3);
419         mul_add_c(a[3],b[6],c1,c2,c3);
420         mul_add_c(a[4],b[5],c1,c2,c3);
421         mul_add_c(a[5],b[4],c1,c2,c3);
422         mul_add_c(a[6],b[3],c1,c2,c3);
423         mul_add_c(a[7],b[2],c1,c2,c3);
424         r[9]=c1;
425         c1=0;
426         mul_add_c(a[7],b[3],c2,c3,c1);
427         mul_add_c(a[6],b[4],c2,c3,c1);
428         mul_add_c(a[5],b[5],c2,c3,c1);
429         mul_add_c(a[4],b[6],c2,c3,c1);
430         mul_add_c(a[3],b[7],c2,c3,c1);
431         r[10]=c2;
432         c2=0;
433         mul_add_c(a[4],b[7],c3,c1,c2);
434         mul_add_c(a[5],b[6],c3,c1,c2);
435         mul_add_c(a[6],b[5],c3,c1,c2);
436         mul_add_c(a[7],b[4],c3,c1,c2);
437         r[11]=c3;
438         c3=0;
439         mul_add_c(a[7],b[5],c1,c2,c3);
440         mul_add_c(a[6],b[6],c1,c2,c3);
441         mul_add_c(a[5],b[7],c1,c2,c3);
442         r[12]=c1;
443         c1=0;
444         mul_add_c(a[6],b[7],c2,c3,c1);
445         mul_add_c(a[7],b[6],c2,c3,c1);
446         r[13]=c2;
447         c2=0;
448         mul_add_c(a[7],b[7],c3,c1,c2);
449         r[14]=c3;
450         r[15]=c1;
451         }
452
453 void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
454         {
455         BN_ULONG t1,t2;
456         BN_ULONG c1,c2,c3;
457
458         c1=0;
459         c2=0;
460         c3=0;
461         mul_add_c(a[0],b[0],c1,c2,c3);
462         r[0]=c1;
463         c1=0;
464         mul_add_c(a[0],b[1],c2,c3,c1);
465         mul_add_c(a[1],b[0],c2,c3,c1);
466         r[1]=c2;
467         c2=0;
468         mul_add_c(a[2],b[0],c3,c1,c2);
469         mul_add_c(a[1],b[1],c3,c1,c2);
470         mul_add_c(a[0],b[2],c3,c1,c2);
471         r[2]=c3;
472         c3=0;
473         mul_add_c(a[0],b[3],c1,c2,c3);
474         mul_add_c(a[1],b[2],c1,c2,c3);
475         mul_add_c(a[2],b[1],c1,c2,c3);
476         mul_add_c(a[3],b[0],c1,c2,c3);
477         r[3]=c1;
478         c1=0;
479         mul_add_c(a[3],b[1],c2,c3,c1);
480         mul_add_c(a[2],b[2],c2,c3,c1);
481         mul_add_c(a[1],b[3],c2,c3,c1);
482         r[4]=c2;
483         c2=0;
484         mul_add_c(a[2],b[3],c3,c1,c2);
485         mul_add_c(a[3],b[2],c3,c1,c2);
486         r[5]=c3;
487         c3=0;
488         mul_add_c(a[3],b[3],c1,c2,c3);
489         r[6]=c1;
490         r[7]=c2;
491         }
492
493 void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a)
494         {
495         BN_ULONG t1,t2;
496         BN_ULONG c1,c2,c3;
497
498         c1=0;
499         c2=0;
500         c3=0;
501         sqr_add_c(a,0,c1,c2,c3);
502         r[0]=c1;
503         c1=0;
504         sqr_add_c2(a,1,0,c2,c3,c1);
505         r[1]=c2;
506         c2=0;
507         sqr_add_c(a,1,c3,c1,c2);
508         sqr_add_c2(a,2,0,c3,c1,c2);
509         r[2]=c3;
510         c3=0;
511         sqr_add_c2(a,3,0,c1,c2,c3);
512         sqr_add_c2(a,2,1,c1,c2,c3);
513         r[3]=c1;
514         c1=0;
515         sqr_add_c(a,2,c2,c3,c1);
516         sqr_add_c2(a,3,1,c2,c3,c1);
517         sqr_add_c2(a,4,0,c2,c3,c1);
518         r[4]=c2;
519         c2=0;
520         sqr_add_c2(a,5,0,c3,c1,c2);
521         sqr_add_c2(a,4,1,c3,c1,c2);
522         sqr_add_c2(a,3,2,c3,c1,c2);
523         r[5]=c3;
524         c3=0;
525         sqr_add_c(a,3,c1,c2,c3);
526         sqr_add_c2(a,4,2,c1,c2,c3);
527         sqr_add_c2(a,5,1,c1,c2,c3);
528         sqr_add_c2(a,6,0,c1,c2,c3);
529         r[6]=c1;
530         c1=0;
531         sqr_add_c2(a,7,0,c2,c3,c1);
532         sqr_add_c2(a,6,1,c2,c3,c1);
533         sqr_add_c2(a,5,2,c2,c3,c1);
534         sqr_add_c2(a,4,3,c2,c3,c1);
535         r[7]=c2;
536         c2=0;
537         sqr_add_c(a,4,c3,c1,c2);
538         sqr_add_c2(a,5,3,c3,c1,c2);
539         sqr_add_c2(a,6,2,c3,c1,c2);
540         sqr_add_c2(a,7,1,c3,c1,c2);
541         r[8]=c3;
542         c3=0;
543         sqr_add_c2(a,7,2,c1,c2,c3);
544         sqr_add_c2(a,6,3,c1,c2,c3);
545         sqr_add_c2(a,5,4,c1,c2,c3);
546         r[9]=c1;
547         c1=0;
548         sqr_add_c(a,5,c2,c3,c1);
549         sqr_add_c2(a,6,4,c2,c3,c1);
550         sqr_add_c2(a,7,3,c2,c3,c1);
551         r[10]=c2;
552         c2=0;
553         sqr_add_c2(a,7,4,c3,c1,c2);
554         sqr_add_c2(a,6,5,c3,c1,c2);
555         r[11]=c3;
556         c3=0;
557         sqr_add_c(a,6,c1,c2,c3);
558         sqr_add_c2(a,7,5,c1,c2,c3);
559         r[12]=c1;
560         c1=0;
561         sqr_add_c2(a,7,6,c2,c3,c1);
562         r[13]=c2;
563         c2=0;
564         sqr_add_c(a,7,c3,c1,c2);
565         r[14]=c3;
566         r[15]=c1;
567         }
568
569 void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a)
570         {
571         BN_ULONG t1,t2;
572         BN_ULONG c1,c2,c3;
573
574         c1=0;
575         c2=0;
576         c3=0;
577         sqr_add_c(a,0,c1,c2,c3);
578         r[0]=c1;
579         c1=0;
580         sqr_add_c2(a,1,0,c2,c3,c1);
581         r[1]=c2;
582         c2=0;
583         sqr_add_c(a,1,c3,c1,c2);
584         sqr_add_c2(a,2,0,c3,c1,c2);
585         r[2]=c3;
586         c3=0;
587         sqr_add_c2(a,3,0,c1,c2,c3);
588         sqr_add_c2(a,2,1,c1,c2,c3);
589         r[3]=c1;
590         c1=0;
591         sqr_add_c(a,2,c2,c3,c1);
592         sqr_add_c2(a,3,1,c2,c3,c1);
593         r[4]=c2;
594         c2=0;
595         sqr_add_c2(a,3,2,c3,c1,c2);
596         r[5]=c3;
597         c3=0;
598         sqr_add_c(a,3,c1,c2,c3);
599         r[6]=c1;
600         r[7]=c2;
601         }
602 #endif