1 #include "../bn_lcl.h"
   2 #if !(defined(__GNUC__) && __GNUC__>=2)
   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 #ifdef _WIN64
  59 #define BN_ULONG unsigned long long
  60 #else
  61 #define BN_ULONG unsigned long
  62 #endif
  63 
  64 #undef mul
  65 #undef mul_add
  66 #undef sqr
  67 
  68 /*
  69  * "m"(a), "+m"(r)      is the way to favor DirectPath -code;
  70  * "g"(0)               let the compiler to decide where does it
  71  *                      want to keep the value of zero;
  72  */
  73 #define mul_add(r,a,word,carry) do {    \
  74         register BN_ULONG high,low;     \
  75         asm ("mulq %3"                  \
  76                 : "=a"(low),"=d"(high)  \
  77                 : "a"(word),"m"(a)      \
  78                 : "cc");                \
  79         asm ("addq %2,%0; adcq %3,%1"   \
  80                 : "+r"(carry),"+d"(high)\
  81                 : "a"(low),"g"(0)       \
  82                 : "cc");                \
  83         asm ("addq %2,%0; adcq %3,%1"   \
  84                 : "+m"(r),"+d"(high)    \
  85                 : "r"(carry),"g"(0)     \
  86                 : "cc");                \
  87         carry=high;                     \
  88         } while (0)
  89 
  90 #define mul(r,a,word,carry) do {        \
  91         register BN_ULONG high,low;     \
  92         asm ("mulq %3"                  \
  93                 : "=a"(low),"=d"(high)  \
  94                 : "a"(word),"g"(a)      \
  95                 : "cc");                \
  96         asm ("addq %2,%0; adcq %3,%1"   \
  97                 : "+r"(carry),"+d"(high)\
  98                 : "a"(low),"g"(0)       \
  99                 : "cc");                \
 100         (r)=carry, carry=high;          \
 101         } while (0)
 102 
 103 #define sqr(r0,r1,a)                    \
 104         asm ("mulq %2"                  \
 105                 : "=a"(r0),"=d"(r1)     \
 106                 : "a"(a)                \
 107                 : "cc");
 108 
 109 BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w)
 110         {
 111         BN_ULONG c1=0;
 112 
 113         if (num <= 0) return(c1);
 114 
 115         while (num&~3)
 116                 {
 117                 mul_add(rp[0],ap[0],w,c1);
 118                 mul_add(rp[1],ap[1],w,c1);
 119                 mul_add(rp[2],ap[2],w,c1);
 120                 mul_add(rp[3],ap[3],w,c1);
 121                 ap+=4; rp+=4; num-=4;
 122                 }
 123         if (num)
 124                 {
 125                 mul_add(rp[0],ap[0],w,c1); if (--num==0) return c1;
 126                 mul_add(rp[1],ap[1],w,c1); if (--num==0) return c1;
 127                 mul_add(rp[2],ap[2],w,c1); return c1;
 128                 }
 129 
 130         return(c1);
 131         }
 132 
 133 BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w)
 134         {
 135         BN_ULONG c1=0;
 136 
 137         if (num <= 0) return(c1);
 138 
 139         while (num&~3)
 140                 {
 141                 mul(rp[0],ap[0],w,c1);
 142                 mul(rp[1],ap[1],w,c1);
 143                 mul(rp[2],ap[2],w,c1);
 144                 mul(rp[3],ap[3],w,c1);
 145                 ap+=4; rp+=4; num-=4;
 146                 }
 147         if (num)
 148                 {
 149                 mul(rp[0],ap[0],w,c1); if (--num == 0) return c1;
 150                 mul(rp[1],ap[1],w,c1); if (--num == 0) return c1;
 151                 mul(rp[2],ap[2],w,c1);
 152                 }
 153         return(c1);
 154         }
 155 
 156 void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n)
 157         {
 158         if (n <= 0) return;
 159 
 160         while (n&~3)
 161                 {
 162                 sqr(r[0],r[1],a[0]);
 163                 sqr(r[2],r[3],a[1]);
 164                 sqr(r[4],r[5],a[2]);
 165                 sqr(r[6],r[7],a[3]);
 166                 a+=4; r+=8; n-=4;
 167                 }
 168         if (n)
 169                 {
 170                 sqr(r[0],r[1],a[0]); if (--n == 0) return;
 171                 sqr(r[2],r[3],a[1]); if (--n == 0) return;
 172                 sqr(r[4],r[5],a[2]);
 173                 }
 174         }
 175 
 176 BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d)
 177 {       BN_ULONG ret,waste;
 178 
 179         asm ("divq      %4"
 180                 : "=a"(ret),"=d"(waste)
 181                 : "a"(l),"d"(h),"g"(d)
 182                 : "cc");
 183 
 184         return ret;
 185 }
 186 
 187 BN_ULONG bn_add_words (BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int n)
 188 { BN_ULONG ret=0,i=0;
 189 
 190         if (n <= 0) return 0;
 191 
 192         asm (
 193         "       subq    %2,%2           \n"
 194         ".p2align 4                     \n"
 195         "1:     movq    (%4,%2,8),%0    \n"
 196         "       adcq    (%5,%2,8),%0    \n"
 197         "       movq    %0,(%3,%2,8)    \n"
 198         "       leaq    1(%2),%2        \n"
 199         "       loop    1b              \n"
 200         "       sbbq    %0,%0           \n"
 201                 : "=&a"(ret),"+c"(n),"=&r"(i)
 202                 : "r"(rp),"r"(ap),"r"(bp)
 203                 : "cc"
 204         );
 205 
 206   return ret&1;
 207 }
 208 
 209 #ifndef SIMICS
 210 BN_ULONG bn_sub_words (BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int n)
 211 { BN_ULONG ret=0,i=0;
 212 
 213         if (n <= 0) return 0;
 214 
 215         asm (
 216         "       subq    %2,%2           \n"
 217         ".p2align 4                     \n"
 218         "1:     movq    (%4,%2,8),%0    \n"
 219         "       sbbq    (%5,%2,8),%0    \n"
 220         "       movq    %0,(%3,%2,8)    \n"
 221         "       leaq    1(%2),%2        \n"
 222         "       loop    1b              \n"
 223         "       sbbq    %0,%0           \n"
 224                 : "=&a"(ret),"+c"(n),"=&r"(i)
 225                 : "r"(rp),"r"(ap),"r"(bp)
 226                 : "cc"
 227         );
 228 
 229   return ret&1;
 230 }
 231 #else
 232 /* Simics 1.4<7 has buggy sbbq:-( */
 233 #define BN_MASK2 0xffffffffffffffffL
 234 BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
 235         {
 236         BN_ULONG t1,t2;
 237         int c=0;
 238 
 239         if (n <= 0) return((BN_ULONG)0);
 240 
 241         for (;;)
 242                 {
 243                 t1=a[0]; t2=b[0];
 244                 r[0]=(t1-t2-c)&BN_MASK2;
 245                 if (t1 != t2) c=(t1 < t2);
 246                 if (--n <= 0) break;
 247 
 248                 t1=a[1]; t2=b[1];
 249                 r[1]=(t1-t2-c)&BN_MASK2;
 250                 if (t1 != t2) c=(t1 < t2);
 251                 if (--n <= 0) break;
 252 
 253                 t1=a[2]; t2=b[2];
 254                 r[2]=(t1-t2-c)&BN_MASK2;
 255                 if (t1 != t2) c=(t1 < t2);
 256                 if (--n <= 0) break;
 257 
 258                 t1=a[3]; t2=b[3];
 259                 r[3]=(t1-t2-c)&BN_MASK2;
 260                 if (t1 != t2) c=(t1 < t2);
 261                 if (--n <= 0) break;
 262 
 263                 a+=4;
 264                 b+=4;
 265                 r+=4;
 266                 }
 267         return(c);
 268         }
 269 #endif
 270 
 271 /* mul_add_c(a,b,c0,c1,c2)  -- c+=a*b for three word number c=(c2,c1,c0) */
 272 /* mul_add_c2(a,b,c0,c1,c2) -- c+=2*a*b for three word number c=(c2,c1,c0) */
 273 /* sqr_add_c(a,i,c0,c1,c2)  -- c+=a[i]^2 for three word number c=(c2,c1,c0) */
 274 /* sqr_add_c2(a,i,c0,c1,c2) -- c+=2*a[i]*a[j] for three word number c=(c2,c1,c0) */
 275 
 276 #if 0
 277 /* original macros are kept for reference purposes */
 278 #define mul_add_c(a,b,c0,c1,c2) {       \
 279         BN_ULONG ta=(a),tb=(b);         \
 280         t1 = ta * tb;                   \
 281         t2 = BN_UMULT_HIGH(ta,tb);      \
 282         c0 += t1; t2 += (c0<t1)?1:0; \
 283         c1 += t2; c2 += (c1<t2)?1:0; \
 284         }
 285 
 286 #define mul_add_c2(a,b,c0,c1,c2) {      \
 287         BN_ULONG ta=(a),tb=(b),t0;      \
 288         t1 = BN_UMULT_HIGH(ta,tb);      \
 289         t0 = ta * tb;                   \
 290         t2 = t1+t1; c2 += (t2<t1)?1:0;       \
 291         t1 = t0+t0; t2 += (t1<t0)?1:0;       \
 292         c0 += t1; t2 += (c0<t1)?1:0; \
 293         c1 += t2; c2 += (c1<t2)?1:0; \
 294         }
 295 #else
 296 #define mul_add_c(a,b,c0,c1,c2) do {    \
 297         asm ("mulq %3"                  \
 298                 : "=a"(t1),"=d"(t2)     \
 299                 : "a"(a),"m"(b)         \
 300                 : "cc");                \
 301         asm ("addq %2,%0; adcq %3,%1"   \
 302                 : "+r"(c0),"+d"(t2)     \
 303                 : "a"(t1),"g"(0)        \
 304                 : "cc");                \
 305         asm ("addq %2,%0; adcq %3,%1"   \
 306                 : "+r"(c1),"+r"(c2)     \
 307                 : "d"(t2),"g"(0)        \
 308                 : "cc");                \
 309         } while (0)
 310 
 311 #define sqr_add_c(a,i,c0,c1,c2) do {    \
 312         asm ("mulq %2"                  \
 313                 : "=a"(t1),"=d"(t2)     \
 314                 : "a"(a[i])             \
 315                 : "cc");                \
 316         asm ("addq %2,%0; adcq %3,%1"   \
 317                 : "+r"(c0),"+d"(t2)     \
 318                 : "a"(t1),"g"(0)        \
 319                 : "cc");                \
 320         asm ("addq %2,%0; adcq %3,%1"   \
 321                 : "+r"(c1),"+r"(c2)     \
 322                 : "d"(t2),"g"(0)        \
 323                 : "cc");                \
 324         } while (0)
 325 
 326 #define mul_add_c2(a,b,c0,c1,c2) do {   \
 327         asm ("mulq %3"                  \
 328                 : "=a"(t1),"=d"(t2)     \
 329                 : "a"(a),"m"(b)         \
 330                 : "cc");                \
 331         asm ("addq %0,%0; adcq %2,%1"   \
 332                 : "+d"(t2),"+r"(c2)     \
 333                 : "g"(0)                \
 334                 : "cc");                \
 335         asm ("addq %0,%0; adcq %2,%1"   \
 336                 : "+a"(t1),"+d"(t2)     \
 337                 : "g"(0)                \
 338                 : "cc");                \
 339         asm ("addq %2,%0; adcq %3,%1"   \
 340                 : "+r"(c0),"+d"(t2)     \
 341                 : "a"(t1),"g"(0)        \
 342                 : "cc");                \
 343         asm ("addq %2,%0; adcq %3,%1"   \
 344                 : "+r"(c1),"+r"(c2)     \
 345                 : "d"(t2),"g"(0)        \
 346                 : "cc");                \
 347         } while (0)
 348 #endif
 349 
 350 #define sqr_add_c2(a,i,j,c0,c1,c2)      \
 351         mul_add_c2((a)[i],(a)[j],c0,c1,c2)
 352 
 353 void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
 354         {
 355         BN_ULONG t1,t2;
 356         BN_ULONG c1,c2,c3;
 357 
 358         c1=0;
 359         c2=0;
 360         c3=0;
 361         mul_add_c(a[0],b[0],c1,c2,c3);
 362         r[0]=c1;
 363         c1=0;
 364         mul_add_c(a[0],b[1],c2,c3,c1);
 365         mul_add_c(a[1],b[0],c2,c3,c1);
 366         r[1]=c2;
 367         c2=0;
 368         mul_add_c(a[2],b[0],c3,c1,c2);
 369         mul_add_c(a[1],b[1],c3,c1,c2);
 370         mul_add_c(a[0],b[2],c3,c1,c2);
 371         r[2]=c3;
 372         c3=0;
 373         mul_add_c(a[0],b[3],c1,c2,c3);
 374         mul_add_c(a[1],b[2],c1,c2,c3);
 375         mul_add_c(a[2],b[1],c1,c2,c3);
 376         mul_add_c(a[3],b[0],c1,c2,c3);
 377         r[3]=c1;
 378         c1=0;
 379         mul_add_c(a[4],b[0],c2,c3,c1);
 380         mul_add_c(a[3],b[1],c2,c3,c1);
 381         mul_add_c(a[2],b[2],c2,c3,c1);
 382         mul_add_c(a[1],b[3],c2,c3,c1);
 383         mul_add_c(a[0],b[4],c2,c3,c1);
 384         r[4]=c2;
 385         c2=0;
 386         mul_add_c(a[0],b[5],c3,c1,c2);
 387         mul_add_c(a[1],b[4],c3,c1,c2);
 388         mul_add_c(a[2],b[3],c3,c1,c2);
 389         mul_add_c(a[3],b[2],c3,c1,c2);
 390         mul_add_c(a[4],b[1],c3,c1,c2);
 391         mul_add_c(a[5],b[0],c3,c1,c2);
 392         r[5]=c3;
 393         c3=0;
 394         mul_add_c(a[6],b[0],c1,c2,c3);
 395         mul_add_c(a[5],b[1],c1,c2,c3);
 396         mul_add_c(a[4],b[2],c1,c2,c3);
 397         mul_add_c(a[3],b[3],c1,c2,c3);
 398         mul_add_c(a[2],b[4],c1,c2,c3);
 399         mul_add_c(a[1],b[5],c1,c2,c3);
 400         mul_add_c(a[0],b[6],c1,c2,c3);
 401         r[6]=c1;
 402         c1=0;
 403         mul_add_c(a[0],b[7],c2,c3,c1);
 404         mul_add_c(a[1],b[6],c2,c3,c1);
 405         mul_add_c(a[2],b[5],c2,c3,c1);
 406         mul_add_c(a[3],b[4],c2,c3,c1);
 407         mul_add_c(a[4],b[3],c2,c3,c1);
 408         mul_add_c(a[5],b[2],c2,c3,c1);
 409         mul_add_c(a[6],b[1],c2,c3,c1);
 410         mul_add_c(a[7],b[0],c2,c3,c1);
 411         r[7]=c2;
 412         c2=0;
 413         mul_add_c(a[7],b[1],c3,c1,c2);
 414         mul_add_c(a[6],b[2],c3,c1,c2);
 415         mul_add_c(a[5],b[3],c3,c1,c2);
 416         mul_add_c(a[4],b[4],c3,c1,c2);
 417         mul_add_c(a[3],b[5],c3,c1,c2);
 418         mul_add_c(a[2],b[6],c3,c1,c2);
 419         mul_add_c(a[1],b[7],c3,c1,c2);
 420         r[8]=c3;
 421         c3=0;
 422         mul_add_c(a[2],b[7],c1,c2,c3);
 423         mul_add_c(a[3],b[6],c1,c2,c3);
 424         mul_add_c(a[4],b[5],c1,c2,c3);
 425         mul_add_c(a[5],b[4],c1,c2,c3);
 426         mul_add_c(a[6],b[3],c1,c2,c3);
 427         mul_add_c(a[7],b[2],c1,c2,c3);
 428         r[9]=c1;
 429         c1=0;
 430         mul_add_c(a[7],b[3],c2,c3,c1);
 431         mul_add_c(a[6],b[4],c2,c3,c1);
 432         mul_add_c(a[5],b[5],c2,c3,c1);
 433         mul_add_c(a[4],b[6],c2,c3,c1);
 434         mul_add_c(a[3],b[7],c2,c3,c1);
 435         r[10]=c2;
 436         c2=0;
 437         mul_add_c(a[4],b[7],c3,c1,c2);
 438         mul_add_c(a[5],b[6],c3,c1,c2);
 439         mul_add_c(a[6],b[5],c3,c1,c2);
 440         mul_add_c(a[7],b[4],c3,c1,c2);
 441         r[11]=c3;
 442         c3=0;
 443         mul_add_c(a[7],b[5],c1,c2,c3);
 444         mul_add_c(a[6],b[6],c1,c2,c3);
 445         mul_add_c(a[5],b[7],c1,c2,c3);
 446         r[12]=c1;
 447         c1=0;
 448         mul_add_c(a[6],b[7],c2,c3,c1);
 449         mul_add_c(a[7],b[6],c2,c3,c1);
 450         r[13]=c2;
 451         c2=0;
 452         mul_add_c(a[7],b[7],c3,c1,c2);
 453         r[14]=c3;
 454         r[15]=c1;
 455         }
 456 
 457 void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
 458         {
 459         BN_ULONG t1,t2;
 460         BN_ULONG c1,c2,c3;
 461 
 462         c1=0;
 463         c2=0;
 464         c3=0;
 465         mul_add_c(a[0],b[0],c1,c2,c3);
 466         r[0]=c1;
 467         c1=0;
 468         mul_add_c(a[0],b[1],c2,c3,c1);
 469         mul_add_c(a[1],b[0],c2,c3,c1);
 470         r[1]=c2;
 471         c2=0;
 472         mul_add_c(a[2],b[0],c3,c1,c2);
 473         mul_add_c(a[1],b[1],c3,c1,c2);
 474         mul_add_c(a[0],b[2],c3,c1,c2);
 475         r[2]=c3;
 476         c3=0;
 477         mul_add_c(a[0],b[3],c1,c2,c3);
 478         mul_add_c(a[1],b[2],c1,c2,c3);
 479         mul_add_c(a[2],b[1],c1,c2,c3);
 480         mul_add_c(a[3],b[0],c1,c2,c3);
 481         r[3]=c1;
 482         c1=0;
 483         mul_add_c(a[3],b[1],c2,c3,c1);
 484         mul_add_c(a[2],b[2],c2,c3,c1);
 485         mul_add_c(a[1],b[3],c2,c3,c1);
 486         r[4]=c2;
 487         c2=0;
 488         mul_add_c(a[2],b[3],c3,c1,c2);
 489         mul_add_c(a[3],b[2],c3,c1,c2);
 490         r[5]=c3;
 491         c3=0;
 492         mul_add_c(a[3],b[3],c1,c2,c3);
 493         r[6]=c1;
 494         r[7]=c2;
 495         }
 496 
 497 void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a)
 498         {
 499         BN_ULONG t1,t2;
 500         BN_ULONG c1,c2,c3;
 501 
 502         c1=0;
 503         c2=0;
 504         c3=0;
 505         sqr_add_c(a,0,c1,c2,c3);
 506         r[0]=c1;
 507         c1=0;
 508         sqr_add_c2(a,1,0,c2,c3,c1);
 509         r[1]=c2;
 510         c2=0;
 511         sqr_add_c(a,1,c3,c1,c2);
 512         sqr_add_c2(a,2,0,c3,c1,c2);
 513         r[2]=c3;
 514         c3=0;
 515         sqr_add_c2(a,3,0,c1,c2,c3);
 516         sqr_add_c2(a,2,1,c1,c2,c3);
 517         r[3]=c1;
 518         c1=0;
 519         sqr_add_c(a,2,c2,c3,c1);
 520         sqr_add_c2(a,3,1,c2,c3,c1);
 521         sqr_add_c2(a,4,0,c2,c3,c1);
 522         r[4]=c2;
 523         c2=0;
 524         sqr_add_c2(a,5,0,c3,c1,c2);
 525         sqr_add_c2(a,4,1,c3,c1,c2);
 526         sqr_add_c2(a,3,2,c3,c1,c2);
 527         r[5]=c3;
 528         c3=0;
 529         sqr_add_c(a,3,c1,c2,c3);
 530         sqr_add_c2(a,4,2,c1,c2,c3);
 531         sqr_add_c2(a,5,1,c1,c2,c3);
 532         sqr_add_c2(a,6,0,c1,c2,c3);
 533         r[6]=c1;
 534         c1=0;
 535         sqr_add_c2(a,7,0,c2,c3,c1);
 536         sqr_add_c2(a,6,1,c2,c3,c1);
 537         sqr_add_c2(a,5,2,c2,c3,c1);
 538         sqr_add_c2(a,4,3,c2,c3,c1);
 539         r[7]=c2;
 540         c2=0;
 541         sqr_add_c(a,4,c3,c1,c2);
 542         sqr_add_c2(a,5,3,c3,c1,c2);
 543         sqr_add_c2(a,6,2,c3,c1,c2);
 544         sqr_add_c2(a,7,1,c3,c1,c2);
 545         r[8]=c3;
 546         c3=0;
 547         sqr_add_c2(a,7,2,c1,c2,c3);
 548         sqr_add_c2(a,6,3,c1,c2,c3);
 549         sqr_add_c2(a,5,4,c1,c2,c3);
 550         r[9]=c1;
 551         c1=0;
 552         sqr_add_c(a,5,c2,c3,c1);
 553         sqr_add_c2(a,6,4,c2,c3,c1);
 554         sqr_add_c2(a,7,3,c2,c3,c1);
 555         r[10]=c2;
 556         c2=0;
 557         sqr_add_c2(a,7,4,c3,c1,c2);
 558         sqr_add_c2(a,6,5,c3,c1,c2);
 559         r[11]=c3;
 560         c3=0;
 561         sqr_add_c(a,6,c1,c2,c3);
 562         sqr_add_c2(a,7,5,c1,c2,c3);
 563         r[12]=c1;
 564         c1=0;
 565         sqr_add_c2(a,7,6,c2,c3,c1);
 566         r[13]=c2;
 567         c2=0;
 568         sqr_add_c(a,7,c3,c1,c2);
 569         r[14]=c3;
 570         r[15]=c1;
 571         }
 572 
 573 void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a)
 574         {
 575         BN_ULONG t1,t2;
 576         BN_ULONG c1,c2,c3;
 577 
 578         c1=0;
 579         c2=0;
 580         c3=0;
 581         sqr_add_c(a,0,c1,c2,c3);
 582         r[0]=c1;
 583         c1=0;
 584         sqr_add_c2(a,1,0,c2,c3,c1);
 585         r[1]=c2;
 586         c2=0;
 587         sqr_add_c(a,1,c3,c1,c2);
 588         sqr_add_c2(a,2,0,c3,c1,c2);
 589         r[2]=c3;
 590         c3=0;
 591         sqr_add_c2(a,3,0,c1,c2,c3);
 592         sqr_add_c2(a,2,1,c1,c2,c3);
 593         r[3]=c1;
 594         c1=0;
 595         sqr_add_c(a,2,c2,c3,c1);
 596         sqr_add_c2(a,3,1,c2,c3,c1);
 597         r[4]=c2;
 598         c2=0;
 599         sqr_add_c2(a,3,2,c3,c1,c2);
 600         r[5]=c3;
 601         c3=0;
 602         sqr_add_c(a,3,c1,c2,c3);
 603         r[6]=c1;
 604         r[7]=c2;
 605         }
 606 #endif