busybox/networking/tls_pstm_mul_comba.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2017 Denys Vlasenko
   3 *
   4 * Licensed under GPLv2, see file LICENSE in this source tree.
   5 */
   6#include "tls.h"
   7
   8/* The file is taken almost verbatim from matrixssl-3-7-2b-open/crypto/math/.
   9 * Changes are flagged with //bbox
  10 */
  11
  12/**
  13 *      @file    pstm_mul_comba.c
  14 *      @version 33ef80f (HEAD, tag: MATRIXSSL-3-7-2-OPEN, tag: MATRIXSSL-3-7-2-COMM, origin/master, origin/HEAD, master)
  15 *
  16 *      Multiprecision multiplication with Comba technique.
  17 */
  18/*
  19 *      Copyright (c) 2013-2015 INSIDE Secure Corporation
  20 *      Copyright (c) PeerSec Networks, 2002-2011
  21 *      All Rights Reserved
  22 *
  23 *      The latest version of this code is available at http://www.matrixssl.org
  24 *
  25 *      This software is open source; you can redistribute it and/or modify
  26 *      it under the terms of the GNU General Public License as published by
  27 *      the Free Software Foundation; either version 2 of the License, or
  28 *      (at your option) any later version.
  29 *
  30 *      This General Public License does NOT permit incorporating this software
  31 *      into proprietary programs.  If you are unable to comply with the GPL, a
  32 *      commercial license for this software may be purchased from INSIDE at
  33 *      http://www.insidesecure.com/eng/Company/Locations
  34 *
  35 *      This program is distributed in WITHOUT ANY WARRANTY; without even the
  36 *      implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  37 *      See the GNU General Public License for more details.
  38 *
  39 *      You should have received a copy of the GNU General Public License
  40 *      along with this program; if not, write to the Free Software
  41 *      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  42 *      http://www.gnu.org/copyleft/gpl.html
  43 */
  44/******************************************************************************/
  45
  46//bbox
  47//#include "../cryptoApi.h"
  48#ifndef DISABLE_PSTM
  49
  50/******************************************************************************/
  51#if defined(PSTM_X86)
  52/* x86-32 optimized for 32 bit platforms. For 64 bit mode use X86_64 instead */
  53#if !defined(__GNUC__) || !defined(__i386__) || !defined(PSTM_32BIT)
  54#error "PSTM_X86 option requires GCC and 32 bit mode x86 processor"
  55#endif
  56//#pragma message ("Using 32 bit x86 Assembly Optimizations")
  57
  58/* anything you need at the start */
  59#define COMBA_START
  60
  61/* clear the chaining variables */
  62#define COMBA_CLEAR \
  63   c0 = c1 = c2 = 0;
  64
  65/* forward the carry to the next digit */
  66#define COMBA_FORWARD \
  67   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
  68
  69/* store the first sum */
  70#define COMBA_STORE(x) \
  71   x = c0;
  72
  73/* store the second sum [carry] */
  74#define COMBA_STORE2(x) \
  75   x = c1;
  76
  77/* anything you need at the end */
  78#define COMBA_FINI
  79
  80/* this should multiply i and j  */
  81#define MULADD(i, j)                                      \
  82asm(                                                      \
  83         "movl  %6,%%eax     \n\t"                            \
  84         "mull  %7           \n\t"                            \
  85         "addl  %%eax,%0     \n\t"                            \
  86         "adcl  %%edx,%1     \n\t"                            \
  87         "adcl  $0,%2        \n\t"                            \
  88         :"=rm"(c0), "=rm"(c1), "=rm"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","%edx","cc");
  89        //bbox: ^^^ replaced "=r" with "=rm": %ebx is not available on shared build
  90
  91/******************************************************************************/
  92#elif defined(PSTM_X86_64)
  93/* x86-64 optimized */
  94#if !defined(__GNUC__) || !defined(__x86_64__) || !defined(PSTM_64BIT)
  95#error "PSTM_X86_64 option requires PSTM_64BIT, GCC and 64 bit mode x86 processor"
  96#endif
  97//#pragma message ("Using 64 bit x86_64 Assembly Optimizations")
  98
  99/* anything you need at the start */
 100#define COMBA_START
 101
 102/* clear the chaining variables */
 103#define COMBA_CLEAR \
 104c0 = c1 = c2 = 0;
 105
 106/* forward the carry to the next digit */
 107#define COMBA_FORWARD \
 108do { c0 = c1; c1 = c2; c2 = 0; } while (0);
 109
 110/* store the first sum */
 111#define COMBA_STORE(x) \
 112x = c0;
 113
 114/* store the second sum [carry] */
 115#define COMBA_STORE2(x) \
 116x = c1;
 117
 118/* anything you need at the end */
 119#define COMBA_FINI
 120
 121/* this should multiply i and j  */
 122#define MULADD(i, j)                                                                    \
 123asm  (                                                                                                  \
 124        "movq  %6,%%rax     \n\t"                            \
 125        "mulq  %7           \n\t"                            \
 126        "addq  %%rax,%0     \n\t"                            \
 127        "adcq  %%rdx,%1     \n\t"                            \
 128        "adcq  $0,%2        \n\t"                            \
 129        :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "g"(i), "g"(j)  :"%rax","%rdx","cc");
 130
 131/******************************************************************************/
 132#elif defined(PSTM_ARM)
 133/* ARM code */
 134//#pragma message ("Using 32 bit ARM Assembly Optimizations")
 135
 136#define COMBA_START
 137
 138#define COMBA_CLEAR \
 139c0 = c1 = c2 = 0;
 140
 141#define COMBA_FORWARD \
 142do { c0 = c1; c1 = c2; c2 = 0; } while (0);
 143
 144#define COMBA_STORE(x) \
 145x = c0;
 146
 147#define COMBA_STORE2(x) \
 148x = c1;
 149
 150#define COMBA_FINI
 151
 152#define MULADD(i, j)                                          \
 153asm(                                                          \
 154        "  UMULL  r0,r1,%6,%7           \n\t"                     \
 155        "  ADDS   %0,%0,r0              \n\t"                     \
 156        "  ADCS   %1,%1,r1              \n\t"                     \
 157        "  ADC    %2,%2,#0              \n\t"                     \
 158        :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "cc");
 159
 160/******************************************************************************/
 161#elif defined(PSTM_MIPS)
 162/* MIPS32 code */
 163//#pragma message ("Using 32 bit MIPS Assembly Optimizations")
 164
 165#define COMBA_START
 166
 167#define COMBA_CLEAR \
 168c0 = c1 = c2 = 0;
 169
 170#define COMBA_FORWARD \
 171do { c0 = c1; c1 = c2; c2 = 0; } while (0);
 172
 173#define COMBA_STORE(x) \
 174x = c0;
 175
 176#define COMBA_STORE2(x) \
 177x = c1;
 178
 179#define COMBA_FINI
 180
 181#define MULADD(i, j)               \
 182asm(                               \
 183        " multu  %6,%7          \n\t"  \
 184        " mflo   $12            \n\t"  \
 185        " mfhi   $13            \n\t"  \
 186        " addu    %0,%0,$12     \n\t"  \
 187        " sltu   $12,%0,$12     \n\t"  \
 188        " addu    %1,%1,$13     \n\t"  \
 189        " sltu   $13,%1,$13     \n\t"  \
 190        " addu    %1,%1,$12     \n\t"  \
 191        " sltu   $12,%1,$12     \n\t"  \
 192        " addu    %2,%2,$13     \n\t"  \
 193        " addu    %2,%2,$12     \n\t"  \
 194        :"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"$12","$13");
 195
 196/******************************************************************************/
 197#else
 198
 199#define COMBA_START
 200
 201#define COMBA_CLEAR \
 202   c0 = c1 = c2 = 0;
 203
 204#define COMBA_FORWARD \
 205   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
 206
 207#define COMBA_STORE(x) \
 208   x = c0;
 209
 210#define COMBA_STORE2(x) \
 211   x = c1;
 212
 213#define COMBA_FINI
 214
 215#define MULADD(i, j)                                                                                                            \
 216   do { pstm_word t;                                                                                                            \
 217   t = (pstm_word)c0 + ((pstm_word)i) * ((pstm_word)j); c0 = (pstm_digit)t;     \
 218   t = (pstm_word)c1 + (t >> DIGIT_BIT);                                                                        \
 219   c1 = (pstm_digit)t; c2 += (pstm_digit)(t >> DIGIT_BIT);                                      \
 220   } while (0);
 221
 222#endif
 223
 224/******************************************************************************/
 225/* generic PxQ multiplier */
 226//bbox: pool unused
 227#define pstm_mul_comba_gen(pool, A, B, C, paD, paDlen) \
 228        pstm_mul_comba_gen(      A, B, C, paD, paDlen)
 229static int32 pstm_mul_comba_gen(psPool_t *pool, pstm_int *A, pstm_int *B,
 230                        pstm_int *C, pstm_digit *paD, uint32 paDlen)
 231{
 232        int             paDfail, pa; //bbox: was int16
 233        int32       ix, iy, iz, tx, ty;
 234        pstm_digit      c0, c1, c2, *tmpx, *tmpy, *dst;
 235
 236        COMBA_START;
 237        COMBA_CLEAR;
 238
 239        paDfail = 0;
 240        /* get size of output and trim */
 241        pa = A->used + B->used;
 242
 243/*
 244        If c is not large enough grow it and continue
 245*/
 246        if (C->alloc < pa) {
 247                if (pstm_grow(C, pa) != PSTM_OKAY) {
 248                        return PS_MEM_FAIL;
 249                }
 250        }
 251        if (paD != NULL) {
 252                if (paDlen < (sizeof(pstm_digit) * pa)) {
 253                        paDfail = 1; /* have a paD but it's not large enough */
 254                        dst = xzalloc(sizeof(pstm_digit) * pa);//bbox
 255                } else {
 256                        dst = paD;
 257                        memset(dst, 0x0, paDlen);
 258                }
 259        } else {
 260                dst = xzalloc(sizeof(pstm_digit) * pa);//bbox
 261        }
 262
 263        for (ix = 0; ix < pa; ix++) {
 264                /* get offsets into the two bignums */
 265                ty = min(ix, B->used-1);
 266                tx = ix - ty;
 267
 268                /* setup temp aliases */
 269                tmpx = A->dp + tx;
 270                tmpy = B->dp + ty;
 271/*
 272                This is the number of times the loop will iterate, essentially it's
 273                        while (tx++ < a->used && ty-- >= 0) { ... }
 274*/
 275                iy = min(A->used-tx, ty+1);
 276
 277                /* execute loop */
 278                COMBA_FORWARD;
 279                for (iz = 0; iz < iy; ++iz) {
 280                        MULADD(*tmpx++, *tmpy--);
 281                }
 282
 283                /* store term */
 284                COMBA_STORE(dst[ix]);
 285        }
 286        COMBA_FINI;
 287/*
 288        setup dest
 289 */
 290        iy  = C->used;
 291        C->used = pa;
 292        C->sign = A->sign ^ B->sign;
 293        {
 294                pstm_digit *tmpc;
 295                tmpc = C->dp;
 296                for (ix = 0; ix < pa; ix++) {
 297                        *tmpc++ = dst[ix];
 298                }
 299/*
 300                clear unused digits [that existed in the old copy of c]
 301 */
 302                for (; ix < iy; ix++) {
 303                        *tmpc++ = 0;
 304                }
 305        }
 306        pstm_clamp(C);
 307
 308        if ((paD == NULL) || (paDfail == 1)) {
 309                psFree(dst, pool);
 310        }
 311
 312        return PS_SUCCESS;
 313}
 314
 315/******************************************************************************/
 316#ifdef USE_1024_KEY_SPEED_OPTIMIZATIONS
 317static int32 pstm_mul_comba16(pstm_int *A, pstm_int *B, pstm_int *C)
 318{
 319        pstm_digit c0, c1, c2, at[32];
 320
 321        if (C->alloc < 32) {
 322                if (pstm_grow(C, 32) != PSTM_OKAY) {
 323                        return PS_MEM_FAIL;
 324                }
 325        }
 326        memcpy(at, A->dp, 16 * sizeof(pstm_digit));
 327        memcpy(at+16, B->dp, 16 * sizeof(pstm_digit));
 328
 329   COMBA_START;
 330
 331   COMBA_CLEAR;
 332   /* 0 */
 333   MULADD(at[0], at[16]);
 334   COMBA_STORE(C->dp[0]);
 335   /* 1 */
 336   COMBA_FORWARD;
 337   MULADD(at[0], at[17]);    MULADD(at[1], at[16]);
 338   COMBA_STORE(C->dp[1]);
 339   /* 2 */
 340   COMBA_FORWARD;
 341   MULADD(at[0], at[18]);    MULADD(at[1], at[17]);    MULADD(at[2], at[16]);
 342   COMBA_STORE(C->dp[2]);
 343   /* 3 */
 344   COMBA_FORWARD;
 345   MULADD(at[0], at[19]);    MULADD(at[1], at[18]);    MULADD(at[2], at[17]);    MULADD(at[3], at[16]);
 346   COMBA_STORE(C->dp[3]);
 347   /* 4 */
 348   COMBA_FORWARD;
 349   MULADD(at[0], at[20]);    MULADD(at[1], at[19]);    MULADD(at[2], at[18]);    MULADD(at[3], at[17]);    MULADD(at[4], at[16]);
 350   COMBA_STORE(C->dp[4]);
 351   /* 5 */
 352   COMBA_FORWARD;
 353   MULADD(at[0], at[21]);    MULADD(at[1], at[20]);    MULADD(at[2], at[19]);    MULADD(at[3], at[18]);    MULADD(at[4], at[17]);    MULADD(at[5], at[16]);
 354   COMBA_STORE(C->dp[5]);
 355   /* 6 */
 356   COMBA_FORWARD;
 357   MULADD(at[0], at[22]);    MULADD(at[1], at[21]);    MULADD(at[2], at[20]);    MULADD(at[3], at[19]);    MULADD(at[4], at[18]);    MULADD(at[5], at[17]);    MULADD(at[6], at[16]);
 358   COMBA_STORE(C->dp[6]);
 359   /* 7 */
 360   COMBA_FORWARD;
 361   MULADD(at[0], at[23]);    MULADD(at[1], at[22]);    MULADD(at[2], at[21]);    MULADD(at[3], at[20]);    MULADD(at[4], at[19]);    MULADD(at[5], at[18]);    MULADD(at[6], at[17]);    MULADD(at[7], at[16]);
 362   COMBA_STORE(C->dp[7]);
 363   /* 8 */
 364   COMBA_FORWARD;
 365   MULADD(at[0], at[24]);    MULADD(at[1], at[23]);    MULADD(at[2], at[22]);    MULADD(at[3], at[21]);    MULADD(at[4], at[20]);    MULADD(at[5], at[19]);    MULADD(at[6], at[18]);    MULADD(at[7], at[17]);    MULADD(at[8], at[16]);
 366   COMBA_STORE(C->dp[8]);
 367   /* 9 */
 368   COMBA_FORWARD;
 369   MULADD(at[0], at[25]);    MULADD(at[1], at[24]);    MULADD(at[2], at[23]);    MULADD(at[3], at[22]);    MULADD(at[4], at[21]);    MULADD(at[5], at[20]);    MULADD(at[6], at[19]);    MULADD(at[7], at[18]);    MULADD(at[8], at[17]);    MULADD(at[9], at[16]);
 370   COMBA_STORE(C->dp[9]);
 371   /* 10 */
 372   COMBA_FORWARD;
 373   MULADD(at[0], at[26]);    MULADD(at[1], at[25]);    MULADD(at[2], at[24]);    MULADD(at[3], at[23]);    MULADD(at[4], at[22]);    MULADD(at[5], at[21]);    MULADD(at[6], at[20]);    MULADD(at[7], at[19]);    MULADD(at[8], at[18]);    MULADD(at[9], at[17]);    MULADD(at[10], at[16]);
 374   COMBA_STORE(C->dp[10]);
 375   /* 11 */
 376   COMBA_FORWARD;
 377   MULADD(at[0], at[27]);    MULADD(at[1], at[26]);    MULADD(at[2], at[25]);    MULADD(at[3], at[24]);    MULADD(at[4], at[23]);    MULADD(at[5], at[22]);    MULADD(at[6], at[21]);    MULADD(at[7], at[20]);    MULADD(at[8], at[19]);    MULADD(at[9], at[18]);    MULADD(at[10], at[17]);    MULADD(at[11], at[16]);
 378   COMBA_STORE(C->dp[11]);
 379   /* 12 */
 380   COMBA_FORWARD;
 381   MULADD(at[0], at[28]);    MULADD(at[1], at[27]);    MULADD(at[2], at[26]);    MULADD(at[3], at[25]);    MULADD(at[4], at[24]);    MULADD(at[5], at[23]);    MULADD(at[6], at[22]);    MULADD(at[7], at[21]);    MULADD(at[8], at[20]);    MULADD(at[9], at[19]);    MULADD(at[10], at[18]);    MULADD(at[11], at[17]);    MULADD(at[12], at[16]);
 382   COMBA_STORE(C->dp[12]);
 383   /* 13 */
 384   COMBA_FORWARD;
 385   MULADD(at[0], at[29]);    MULADD(at[1], at[28]);    MULADD(at[2], at[27]);    MULADD(at[3], at[26]);    MULADD(at[4], at[25]);    MULADD(at[5], at[24]);    MULADD(at[6], at[23]);    MULADD(at[7], at[22]);    MULADD(at[8], at[21]);    MULADD(at[9], at[20]);    MULADD(at[10], at[19]);    MULADD(at[11], at[18]);    MULADD(at[12], at[17]);    MULADD(at[13], at[16]);
 386   COMBA_STORE(C->dp[13]);
 387   /* 14 */
 388   COMBA_FORWARD;
 389   MULADD(at[0], at[30]);    MULADD(at[1], at[29]);    MULADD(at[2], at[28]);    MULADD(at[3], at[27]);    MULADD(at[4], at[26]);    MULADD(at[5], at[25]);    MULADD(at[6], at[24]);    MULADD(at[7], at[23]);    MULADD(at[8], at[22]);    MULADD(at[9], at[21]);    MULADD(at[10], at[20]);    MULADD(at[11], at[19]);    MULADD(at[12], at[18]);    MULADD(at[13], at[17]);    MULADD(at[14], at[16]);
 390   COMBA_STORE(C->dp[14]);
 391   /* 15 */
 392   COMBA_FORWARD;
 393   MULADD(at[0], at[31]);    MULADD(at[1], at[30]);    MULADD(at[2], at[29]);    MULADD(at[3], at[28]);    MULADD(at[4], at[27]);    MULADD(at[5], at[26]);    MULADD(at[6], at[25]);    MULADD(at[7], at[24]);    MULADD(at[8], at[23]);    MULADD(at[9], at[22]);    MULADD(at[10], at[21]);    MULADD(at[11], at[20]);    MULADD(at[12], at[19]);    MULADD(at[13], at[18]);    MULADD(at[14], at[17]);    MULADD(at[15], at[16]);
 394   COMBA_STORE(C->dp[15]);
 395   /* 16 */
 396   COMBA_FORWARD;
 397   MULADD(at[1], at[31]);    MULADD(at[2], at[30]);    MULADD(at[3], at[29]);    MULADD(at[4], at[28]);    MULADD(at[5], at[27]);    MULADD(at[6], at[26]);    MULADD(at[7], at[25]);    MULADD(at[8], at[24]);    MULADD(at[9], at[23]);    MULADD(at[10], at[22]);    MULADD(at[11], at[21]);    MULADD(at[12], at[20]);    MULADD(at[13], at[19]);    MULADD(at[14], at[18]);    MULADD(at[15], at[17]);
 398   COMBA_STORE(C->dp[16]);
 399   /* 17 */
 400   COMBA_FORWARD;
 401   MULADD(at[2], at[31]);    MULADD(at[3], at[30]);    MULADD(at[4], at[29]);    MULADD(at[5], at[28]);    MULADD(at[6], at[27]);    MULADD(at[7], at[26]);    MULADD(at[8], at[25]);    MULADD(at[9], at[24]);    MULADD(at[10], at[23]);    MULADD(at[11], at[22]);    MULADD(at[12], at[21]);    MULADD(at[13], at[20]);    MULADD(at[14], at[19]);    MULADD(at[15], at[18]);
 402   COMBA_STORE(C->dp[17]);
 403   /* 18 */
 404   COMBA_FORWARD;
 405   MULADD(at[3], at[31]);    MULADD(at[4], at[30]);    MULADD(at[5], at[29]);    MULADD(at[6], at[28]);    MULADD(at[7], at[27]);    MULADD(at[8], at[26]);    MULADD(at[9], at[25]);    MULADD(at[10], at[24]);    MULADD(at[11], at[23]);    MULADD(at[12], at[22]);    MULADD(at[13], at[21]);    MULADD(at[14], at[20]);    MULADD(at[15], at[19]);
 406   COMBA_STORE(C->dp[18]);
 407   /* 19 */
 408   COMBA_FORWARD;
 409   MULADD(at[4], at[31]);    MULADD(at[5], at[30]);    MULADD(at[6], at[29]);    MULADD(at[7], at[28]);    MULADD(at[8], at[27]);    MULADD(at[9], at[26]);    MULADD(at[10], at[25]);    MULADD(at[11], at[24]);    MULADD(at[12], at[23]);    MULADD(at[13], at[22]);    MULADD(at[14], at[21]);    MULADD(at[15], at[20]);
 410   COMBA_STORE(C->dp[19]);
 411   /* 20 */
 412   COMBA_FORWARD;
 413   MULADD(at[5], at[31]);    MULADD(at[6], at[30]);    MULADD(at[7], at[29]);    MULADD(at[8], at[28]);    MULADD(at[9], at[27]);    MULADD(at[10], at[26]);    MULADD(at[11], at[25]);    MULADD(at[12], at[24]);    MULADD(at[13], at[23]);    MULADD(at[14], at[22]);    MULADD(at[15], at[21]);
 414   COMBA_STORE(C->dp[20]);
 415   /* 21 */
 416   COMBA_FORWARD;
 417   MULADD(at[6], at[31]);    MULADD(at[7], at[30]);    MULADD(at[8], at[29]);    MULADD(at[9], at[28]);    MULADD(at[10], at[27]);    MULADD(at[11], at[26]);    MULADD(at[12], at[25]);    MULADD(at[13], at[24]);    MULADD(at[14], at[23]);    MULADD(at[15], at[22]);
 418   COMBA_STORE(C->dp[21]);
 419   /* 22 */
 420   COMBA_FORWARD;
 421   MULADD(at[7], at[31]);    MULADD(at[8], at[30]);    MULADD(at[9], at[29]);    MULADD(at[10], at[28]);    MULADD(at[11], at[27]);    MULADD(at[12], at[26]);    MULADD(at[13], at[25]);    MULADD(at[14], at[24]);    MULADD(at[15], at[23]);
 422   COMBA_STORE(C->dp[22]);
 423   /* 23 */
 424   COMBA_FORWARD;
 425   MULADD(at[8], at[31]);    MULADD(at[9], at[30]);    MULADD(at[10], at[29]);    MULADD(at[11], at[28]);    MULADD(at[12], at[27]);    MULADD(at[13], at[26]);    MULADD(at[14], at[25]);    MULADD(at[15], at[24]);
 426   COMBA_STORE(C->dp[23]);
 427   /* 24 */
 428   COMBA_FORWARD;
 429   MULADD(at[9], at[31]);    MULADD(at[10], at[30]);    MULADD(at[11], at[29]);    MULADD(at[12], at[28]);    MULADD(at[13], at[27]);    MULADD(at[14], at[26]);    MULADD(at[15], at[25]);
 430   COMBA_STORE(C->dp[24]);
 431   /* 25 */
 432   COMBA_FORWARD;
 433   MULADD(at[10], at[31]);    MULADD(at[11], at[30]);    MULADD(at[12], at[29]);    MULADD(at[13], at[28]);    MULADD(at[14], at[27]);    MULADD(at[15], at[26]);
 434   COMBA_STORE(C->dp[25]);
 435   /* 26 */
 436   COMBA_FORWARD;
 437   MULADD(at[11], at[31]);    MULADD(at[12], at[30]);    MULADD(at[13], at[29]);    MULADD(at[14], at[28]);    MULADD(at[15], at[27]);
 438   COMBA_STORE(C->dp[26]);
 439   /* 27 */
 440   COMBA_FORWARD;
 441   MULADD(at[12], at[31]);    MULADD(at[13], at[30]);    MULADD(at[14], at[29]);    MULADD(at[15], at[28]);
 442   COMBA_STORE(C->dp[27]);
 443   /* 28 */
 444   COMBA_FORWARD;
 445   MULADD(at[13], at[31]);    MULADD(at[14], at[30]);    MULADD(at[15], at[29]);
 446   COMBA_STORE(C->dp[28]);
 447   /* 29 */
 448   COMBA_FORWARD;
 449   MULADD(at[14], at[31]);    MULADD(at[15], at[30]);
 450   COMBA_STORE(C->dp[29]);
 451   /* 30 */
 452   COMBA_FORWARD;
 453   MULADD(at[15], at[31]);
 454   COMBA_STORE(C->dp[30]);
 455   COMBA_STORE2(C->dp[31]);
 456   C->used = 32;
 457   C->sign = A->sign ^ B->sign;
 458   pstm_clamp(C);
 459   COMBA_FINI;
 460   return PSTM_OKAY;
 461}
 462#endif /* USE_1024_KEY_SPEED_OPTIMIZATIONS */
 463
 464
 465#ifdef USE_2048_KEY_SPEED_OPTIMIZATIONS
 466static int32 pstm_mul_comba32(pstm_int *A, pstm_int *B, pstm_int *C)
 467{
 468   pstm_digit c0, c1, c2, at[64];
 469   int32 out_size;
 470
 471        if (C->alloc < 64) {
 472                if (pstm_grow(C, 64) != PSTM_OKAY) {
 473                        return PS_MEM_FAIL;
 474                }
 475        }
 476
 477   out_size = A->used + B->used;
 478   memcpy(at, A->dp, 32 * sizeof(pstm_digit));
 479   memcpy(at+32, B->dp, 32 * sizeof(pstm_digit));
 480   COMBA_START;
 481
 482   COMBA_CLEAR;
 483   /* 0 */
 484   MULADD(at[0], at[32]);
 485   COMBA_STORE(C->dp[0]);
 486   /* 1 */
 487   COMBA_FORWARD;
 488   MULADD(at[0], at[33]);    MULADD(at[1], at[32]);
 489   COMBA_STORE(C->dp[1]);
 490   /* 2 */
 491   COMBA_FORWARD;
 492   MULADD(at[0], at[34]);    MULADD(at[1], at[33]);    MULADD(at[2], at[32]);
 493   COMBA_STORE(C->dp[2]);
 494   /* 3 */
 495   COMBA_FORWARD;
 496   MULADD(at[0], at[35]);    MULADD(at[1], at[34]);    MULADD(at[2], at[33]);    MULADD(at[3], at[32]);
 497   COMBA_STORE(C->dp[3]);
 498   /* 4 */
 499   COMBA_FORWARD;
 500   MULADD(at[0], at[36]);    MULADD(at[1], at[35]);    MULADD(at[2], at[34]);    MULADD(at[3], at[33]);    MULADD(at[4], at[32]);
 501   COMBA_STORE(C->dp[4]);
 502   /* 5 */
 503   COMBA_FORWARD;
 504   MULADD(at[0], at[37]);    MULADD(at[1], at[36]);    MULADD(at[2], at[35]);    MULADD(at[3], at[34]);    MULADD(at[4], at[33]);    MULADD(at[5], at[32]);
 505   COMBA_STORE(C->dp[5]);
 506   /* 6 */
 507   COMBA_FORWARD;
 508   MULADD(at[0], at[38]);    MULADD(at[1], at[37]);    MULADD(at[2], at[36]);    MULADD(at[3], at[35]);    MULADD(at[4], at[34]);    MULADD(at[5], at[33]);    MULADD(at[6], at[32]);
 509   COMBA_STORE(C->dp[6]);
 510   /* 7 */
 511   COMBA_FORWARD;
 512   MULADD(at[0], at[39]);    MULADD(at[1], at[38]);    MULADD(at[2], at[37]);    MULADD(at[3], at[36]);    MULADD(at[4], at[35]);    MULADD(at[5], at[34]);    MULADD(at[6], at[33]);    MULADD(at[7], at[32]);
 513   COMBA_STORE(C->dp[7]);
 514   /* 8 */
 515   COMBA_FORWARD;
 516   MULADD(at[0], at[40]);    MULADD(at[1], at[39]);    MULADD(at[2], at[38]);    MULADD(at[3], at[37]);    MULADD(at[4], at[36]);    MULADD(at[5], at[35]);    MULADD(at[6], at[34]);    MULADD(at[7], at[33]);    MULADD(at[8], at[32]);
 517   COMBA_STORE(C->dp[8]);
 518   /* 9 */
 519   COMBA_FORWARD;
 520   MULADD(at[0], at[41]);    MULADD(at[1], at[40]);    MULADD(at[2], at[39]);    MULADD(at[3], at[38]);    MULADD(at[4], at[37]);    MULADD(at[5], at[36]);    MULADD(at[6], at[35]);    MULADD(at[7], at[34]);    MULADD(at[8], at[33]);    MULADD(at[9], at[32]);
 521   COMBA_STORE(C->dp[9]);
 522   /* 10 */
 523   COMBA_FORWARD;
 524   MULADD(at[0], at[42]);    MULADD(at[1], at[41]);    MULADD(at[2], at[40]);    MULADD(at[3], at[39]);    MULADD(at[4], at[38]);    MULADD(at[5], at[37]);    MULADD(at[6], at[36]);    MULADD(at[7], at[35]);    MULADD(at[8], at[34]);    MULADD(at[9], at[33]);    MULADD(at[10], at[32]);
 525   COMBA_STORE(C->dp[10]);
 526   /* 11 */
 527   COMBA_FORWARD;
 528   MULADD(at[0], at[43]);    MULADD(at[1], at[42]);    MULADD(at[2], at[41]);    MULADD(at[3], at[40]);    MULADD(at[4], at[39]);    MULADD(at[5], at[38]);    MULADD(at[6], at[37]);    MULADD(at[7], at[36]);    MULADD(at[8], at[35]);    MULADD(at[9], at[34]);    MULADD(at[10], at[33]);    MULADD(at[11], at[32]);
 529   COMBA_STORE(C->dp[11]);
 530   /* 12 */
 531   COMBA_FORWARD;
 532   MULADD(at[0], at[44]);    MULADD(at[1], at[43]);    MULADD(at[2], at[42]);    MULADD(at[3], at[41]);    MULADD(at[4], at[40]);    MULADD(at[5], at[39]);    MULADD(at[6], at[38]);    MULADD(at[7], at[37]);    MULADD(at[8], at[36]);    MULADD(at[9], at[35]);    MULADD(at[10], at[34]);    MULADD(at[11], at[33]);    MULADD(at[12], at[32]);
 533   COMBA_STORE(C->dp[12]);
 534   /* 13 */
 535   COMBA_FORWARD;
 536   MULADD(at[0], at[45]);    MULADD(at[1], at[44]);    MULADD(at[2], at[43]);    MULADD(at[3], at[42]);    MULADD(at[4], at[41]);    MULADD(at[5], at[40]);    MULADD(at[6], at[39]);    MULADD(at[7], at[38]);    MULADD(at[8], at[37]);    MULADD(at[9], at[36]);    MULADD(at[10], at[35]);    MULADD(at[11], at[34]);    MULADD(at[12], at[33]);    MULADD(at[13], at[32]);
 537   COMBA_STORE(C->dp[13]);
 538   /* 14 */
 539   COMBA_FORWARD;
 540   MULADD(at[0], at[46]);    MULADD(at[1], at[45]);    MULADD(at[2], at[44]);    MULADD(at[3], at[43]);    MULADD(at[4], at[42]);    MULADD(at[5], at[41]);    MULADD(at[6], at[40]);    MULADD(at[7], at[39]);    MULADD(at[8], at[38]);    MULADD(at[9], at[37]);    MULADD(at[10], at[36]);    MULADD(at[11], at[35]);    MULADD(at[12], at[34]);    MULADD(at[13], at[33]);    MULADD(at[14], at[32]);
 541   COMBA_STORE(C->dp[14]);
 542   /* 15 */
 543   COMBA_FORWARD;
 544   MULADD(at[0], at[47]);    MULADD(at[1], at[46]);    MULADD(at[2], at[45]);    MULADD(at[3], at[44]);    MULADD(at[4], at[43]);    MULADD(at[5], at[42]);    MULADD(at[6], at[41]);    MULADD(at[7], at[40]);    MULADD(at[8], at[39]);    MULADD(at[9], at[38]);    MULADD(at[10], at[37]);    MULADD(at[11], at[36]);    MULADD(at[12], at[35]);    MULADD(at[13], at[34]);    MULADD(at[14], at[33]);    MULADD(at[15], at[32]);
 545   COMBA_STORE(C->dp[15]);
 546   /* 16 */
 547   COMBA_FORWARD;
 548   MULADD(at[0], at[48]);    MULADD(at[1], at[47]);    MULADD(at[2], at[46]);    MULADD(at[3], at[45]);    MULADD(at[4], at[44]);    MULADD(at[5], at[43]);    MULADD(at[6], at[42]);    MULADD(at[7], at[41]);    MULADD(at[8], at[40]);    MULADD(at[9], at[39]);    MULADD(at[10], at[38]);    MULADD(at[11], at[37]);    MULADD(at[12], at[36]);    MULADD(at[13], at[35]);    MULADD(at[14], at[34]);    MULADD(at[15], at[33]);    MULADD(at[16], at[32]);
 549   COMBA_STORE(C->dp[16]);
 550   /* 17 */
 551   COMBA_FORWARD;
 552   MULADD(at[0], at[49]);    MULADD(at[1], at[48]);    MULADD(at[2], at[47]);    MULADD(at[3], at[46]);    MULADD(at[4], at[45]);    MULADD(at[5], at[44]);    MULADD(at[6], at[43]);    MULADD(at[7], at[42]);    MULADD(at[8], at[41]);    MULADD(at[9], at[40]);    MULADD(at[10], at[39]);    MULADD(at[11], at[38]);    MULADD(at[12], at[37]);    MULADD(at[13], at[36]);    MULADD(at[14], at[35]);    MULADD(at[15], at[34]);    MULADD(at[16], at[33]);    MULADD(at[17], at[32]);
 553   COMBA_STORE(C->dp[17]);
 554   /* 18 */
 555   COMBA_FORWARD;
 556   MULADD(at[0], at[50]);    MULADD(at[1], at[49]);    MULADD(at[2], at[48]);    MULADD(at[3], at[47]);    MULADD(at[4], at[46]);    MULADD(at[5], at[45]);    MULADD(at[6], at[44]);    MULADD(at[7], at[43]);    MULADD(at[8], at[42]);    MULADD(at[9], at[41]);    MULADD(at[10], at[40]);    MULADD(at[11], at[39]);    MULADD(at[12], at[38]);    MULADD(at[13], at[37]);    MULADD(at[14], at[36]);    MULADD(at[15], at[35]);    MULADD(at[16], at[34]);    MULADD(at[17], at[33]);    MULADD(at[18], at[32]);
 557   COMBA_STORE(C->dp[18]);
 558   /* 19 */
 559   COMBA_FORWARD;
 560   MULADD(at[0], at[51]);    MULADD(at[1], at[50]);    MULADD(at[2], at[49]);    MULADD(at[3], at[48]);    MULADD(at[4], at[47]);    MULADD(at[5], at[46]);    MULADD(at[6], at[45]);    MULADD(at[7], at[44]);    MULADD(at[8], at[43]);    MULADD(at[9], at[42]);    MULADD(at[10], at[41]);    MULADD(at[11], at[40]);    MULADD(at[12], at[39]);    MULADD(at[13], at[38]);    MULADD(at[14], at[37]);    MULADD(at[15], at[36]);    MULADD(at[16], at[35]);    MULADD(at[17], at[34]);    MULADD(at[18], at[33]);    MULADD(at[19], at[32]);
 561   COMBA_STORE(C->dp[19]);
 562   /* 20 */
 563   COMBA_FORWARD;
 564   MULADD(at[0], at[52]);    MULADD(at[1], at[51]);    MULADD(at[2], at[50]);    MULADD(at[3], at[49]);    MULADD(at[4], at[48]);    MULADD(at[5], at[47]);    MULADD(at[6], at[46]);    MULADD(at[7], at[45]);    MULADD(at[8], at[44]);    MULADD(at[9], at[43]);    MULADD(at[10], at[42]);    MULADD(at[11], at[41]);    MULADD(at[12], at[40]);    MULADD(at[13], at[39]);    MULADD(at[14], at[38]);    MULADD(at[15], at[37]);    MULADD(at[16], at[36]);    MULADD(at[17], at[35]);    MULADD(at[18], at[34]);    MULADD(at[19], at[33]);    MULADD(at[20], at[32]);
 565   COMBA_STORE(C->dp[20]);
 566   /* 21 */
 567   COMBA_FORWARD;
 568   MULADD(at[0], at[53]);    MULADD(at[1], at[52]);    MULADD(at[2], at[51]);    MULADD(at[3], at[50]);    MULADD(at[4], at[49]);    MULADD(at[5], at[48]);    MULADD(at[6], at[47]);    MULADD(at[7], at[46]);    MULADD(at[8], at[45]);    MULADD(at[9], at[44]);    MULADD(at[10], at[43]);    MULADD(at[11], at[42]);    MULADD(at[12], at[41]);    MULADD(at[13], at[40]);    MULADD(at[14], at[39]);    MULADD(at[15], at[38]);    MULADD(at[16], at[37]);    MULADD(at[17], at[36]);    MULADD(at[18], at[35]);    MULADD(at[19], at[34]);    MULADD(at[20], at[33]);    MULADD(at[21], at[32]);
 569   COMBA_STORE(C->dp[21]);
 570   /* 22 */
 571   COMBA_FORWARD;
 572   MULADD(at[0], at[54]);    MULADD(at[1], at[53]);    MULADD(at[2], at[52]);    MULADD(at[3], at[51]);    MULADD(at[4], at[50]);    MULADD(at[5], at[49]);    MULADD(at[6], at[48]);    MULADD(at[7], at[47]);    MULADD(at[8], at[46]);    MULADD(at[9], at[45]);    MULADD(at[10], at[44]);    MULADD(at[11], at[43]);    MULADD(at[12], at[42]);    MULADD(at[13], at[41]);    MULADD(at[14], at[40]);    MULADD(at[15], at[39]);    MULADD(at[16], at[38]);    MULADD(at[17], at[37]);    MULADD(at[18], at[36]);    MULADD(at[19], at[35]);    MULADD(at[20], at[34]);    MULADD(at[21], at[33]);    MULADD(at[22], at[32]);
 573   COMBA_STORE(C->dp[22]);
 574   /* 23 */
 575   COMBA_FORWARD;
 576   MULADD(at[0], at[55]);    MULADD(at[1], at[54]);    MULADD(at[2], at[53]);    MULADD(at[3], at[52]);    MULADD(at[4], at[51]);    MULADD(at[5], at[50]);    MULADD(at[6], at[49]);    MULADD(at[7], at[48]);    MULADD(at[8], at[47]);    MULADD(at[9], at[46]);    MULADD(at[10], at[45]);    MULADD(at[11], at[44]);    MULADD(at[12], at[43]);    MULADD(at[13], at[42]);    MULADD(at[14], at[41]);    MULADD(at[15], at[40]);    MULADD(at[16], at[39]);    MULADD(at[17], at[38]);    MULADD(at[18], at[37]);    MULADD(at[19], at[36]);    MULADD(at[20], at[35]);    MULADD(at[21], at[34]);    MULADD(at[22], at[33]);    MULADD(at[23], at[32]);
 577   COMBA_STORE(C->dp[23]);
 578   /* 24 */
 579   COMBA_FORWARD;
 580   MULADD(at[0], at[56]);    MULADD(at[1], at[55]);    MULADD(at[2], at[54]);    MULADD(at[3], at[53]);    MULADD(at[4], at[52]);    MULADD(at[5], at[51]);    MULADD(at[6], at[50]);    MULADD(at[7], at[49]);    MULADD(at[8], at[48]);    MULADD(at[9], at[47]);    MULADD(at[10], at[46]);    MULADD(at[11], at[45]);    MULADD(at[12], at[44]);    MULADD(at[13], at[43]);    MULADD(at[14], at[42]);    MULADD(at[15], at[41]);    MULADD(at[16], at[40]);    MULADD(at[17], at[39]);    MULADD(at[18], at[38]);    MULADD(at[19], at[37]);    MULADD(at[20], at[36]);    MULADD(at[21], at[35]);    MULADD(at[22], at[34]);    MULADD(at[23], at[33]);    MULADD(at[24], at[32]);
 581   COMBA_STORE(C->dp[24]);
 582   /* 25 */
 583   COMBA_FORWARD;
 584   MULADD(at[0], at[57]);    MULADD(at[1], at[56]);    MULADD(at[2], at[55]);    MULADD(at[3], at[54]);    MULADD(at[4], at[53]);    MULADD(at[5], at[52]);    MULADD(at[6], at[51]);    MULADD(at[7], at[50]);    MULADD(at[8], at[49]);    MULADD(at[9], at[48]);    MULADD(at[10], at[47]);    MULADD(at[11], at[46]);    MULADD(at[12], at[45]);    MULADD(at[13], at[44]);    MULADD(at[14], at[43]);    MULADD(at[15], at[42]);    MULADD(at[16], at[41]);    MULADD(at[17], at[40]);    MULADD(at[18], at[39]);    MULADD(at[19], at[38]);    MULADD(at[20], at[37]);    MULADD(at[21], at[36]);    MULADD(at[22], at[35]);    MULADD(at[23], at[34]);    MULADD(at[24], at[33]);    MULADD(at[25], at[32]);
 585   COMBA_STORE(C->dp[25]);
 586   /* 26 */
 587   COMBA_FORWARD;
 588   MULADD(at[0], at[58]);    MULADD(at[1], at[57]);    MULADD(at[2], at[56]);    MULADD(at[3], at[55]);    MULADD(at[4], at[54]);    MULADD(at[5], at[53]);    MULADD(at[6], at[52]);    MULADD(at[7], at[51]);    MULADD(at[8], at[50]);    MULADD(at[9], at[49]);    MULADD(at[10], at[48]);    MULADD(at[11], at[47]);    MULADD(at[12], at[46]);    MULADD(at[13], at[45]);    MULADD(at[14], at[44]);    MULADD(at[15], at[43]);    MULADD(at[16], at[42]);    MULADD(at[17], at[41]);    MULADD(at[18], at[40]);    MULADD(at[19], at[39]);    MULADD(at[20], at[38]);    MULADD(at[21], at[37]);    MULADD(at[22], at[36]);    MULADD(at[23], at[35]);    MULADD(at[24], at[34]);    MULADD(at[25], at[33]);    MULADD(at[26], at[32]);
 589   COMBA_STORE(C->dp[26]);
 590   /* 27 */
 591   COMBA_FORWARD;
 592   MULADD(at[0], at[59]);    MULADD(at[1], at[58]);    MULADD(at[2], at[57]);    MULADD(at[3], at[56]);    MULADD(at[4], at[55]);    MULADD(at[5], at[54]);    MULADD(at[6], at[53]);    MULADD(at[7], at[52]);    MULADD(at[8], at[51]);    MULADD(at[9], at[50]);    MULADD(at[10], at[49]);    MULADD(at[11], at[48]);    MULADD(at[12], at[47]);    MULADD(at[13], at[46]);    MULADD(at[14], at[45]);    MULADD(at[15], at[44]);    MULADD(at[16], at[43]);    MULADD(at[17], at[42]);    MULADD(at[18], at[41]);    MULADD(at[19], at[40]);    MULADD(at[20], at[39]);    MULADD(at[21], at[38]);    MULADD(at[22], at[37]);    MULADD(at[23], at[36]);    MULADD(at[24], at[35]);    MULADD(at[25], at[34]);    MULADD(at[26], at[33]);    MULADD(at[27], at[32]);
 593   COMBA_STORE(C->dp[27]);
 594   /* 28 */
 595   COMBA_FORWARD;
 596   MULADD(at[0], at[60]);    MULADD(at[1], at[59]);    MULADD(at[2], at[58]);    MULADD(at[3], at[57]);    MULADD(at[4], at[56]);    MULADD(at[5], at[55]);    MULADD(at[6], at[54]);    MULADD(at[7], at[53]);    MULADD(at[8], at[52]);    MULADD(at[9], at[51]);    MULADD(at[10], at[50]);    MULADD(at[11], at[49]);    MULADD(at[12], at[48]);    MULADD(at[13], at[47]);    MULADD(at[14], at[46]);    MULADD(at[15], at[45]);    MULADD(at[16], at[44]);    MULADD(at[17], at[43]);    MULADD(at[18], at[42]);    MULADD(at[19], at[41]);    MULADD(at[20], at[40]);    MULADD(at[21], at[39]);    MULADD(at[22], at[38]);    MULADD(at[23], at[37]);    MULADD(at[24], at[36]);    MULADD(at[25], at[35]);    MULADD(at[26], at[34]);    MULADD(at[27], at[33]);    MULADD(at[28], at[32]);
 597   COMBA_STORE(C->dp[28]);
 598   /* 29 */
 599   COMBA_FORWARD;
 600   MULADD(at[0], at[61]);    MULADD(at[1], at[60]);    MULADD(at[2], at[59]);    MULADD(at[3], at[58]);    MULADD(at[4], at[57]);    MULADD(at[5], at[56]);    MULADD(at[6], at[55]);    MULADD(at[7], at[54]);    MULADD(at[8], at[53]);    MULADD(at[9], at[52]);    MULADD(at[10], at[51]);    MULADD(at[11], at[50]);    MULADD(at[12], at[49]);    MULADD(at[13], at[48]);    MULADD(at[14], at[47]);    MULADD(at[15], at[46]);    MULADD(at[16], at[45]);    MULADD(at[17], at[44]);    MULADD(at[18], at[43]);    MULADD(at[19], at[42]);    MULADD(at[20], at[41]);    MULADD(at[21], at[40]);    MULADD(at[22], at[39]);    MULADD(at[23], at[38]);    MULADD(at[24], at[37]);    MULADD(at[25], at[36]);    MULADD(at[26], at[35]);    MULADD(at[27], at[34]);    MULADD(at[28], at[33]);    MULADD(at[29], at[32]);
 601   COMBA_STORE(C->dp[29]);
 602   /* 30 */
 603   COMBA_FORWARD;
 604   MULADD(at[0], at[62]);    MULADD(at[1], at[61]);    MULADD(at[2], at[60]);    MULADD(at[3], at[59]);    MULADD(at[4], at[58]);    MULADD(at[5], at[57]);    MULADD(at[6], at[56]);    MULADD(at[7], at[55]);    MULADD(at[8], at[54]);    MULADD(at[9], at[53]);    MULADD(at[10], at[52]);    MULADD(at[11], at[51]);    MULADD(at[12], at[50]);    MULADD(at[13], at[49]);    MULADD(at[14], at[48]);    MULADD(at[15], at[47]);    MULADD(at[16], at[46]);    MULADD(at[17], at[45]);    MULADD(at[18], at[44]);    MULADD(at[19], at[43]);    MULADD(at[20], at[42]);    MULADD(at[21], at[41]);    MULADD(at[22], at[40]);    MULADD(at[23], at[39]);    MULADD(at[24], at[38]);    MULADD(at[25], at[37]);    MULADD(at[26], at[36]);    MULADD(at[27], at[35]);    MULADD(at[28], at[34]);    MULADD(at[29], at[33]);    MULADD(at[30], at[32]);
 605   COMBA_STORE(C->dp[30]);
 606   /* 31 */
 607   COMBA_FORWARD;
 608   MULADD(at[0], at[63]);    MULADD(at[1], at[62]);    MULADD(at[2], at[61]);    MULADD(at[3], at[60]);    MULADD(at[4], at[59]);    MULADD(at[5], at[58]);    MULADD(at[6], at[57]);    MULADD(at[7], at[56]);    MULADD(at[8], at[55]);    MULADD(at[9], at[54]);    MULADD(at[10], at[53]);    MULADD(at[11], at[52]);    MULADD(at[12], at[51]);    MULADD(at[13], at[50]);    MULADD(at[14], at[49]);    MULADD(at[15], at[48]);    MULADD(at[16], at[47]);    MULADD(at[17], at[46]);    MULADD(at[18], at[45]);    MULADD(at[19], at[44]);    MULADD(at[20], at[43]);    MULADD(at[21], at[42]);    MULADD(at[22], at[41]);    MULADD(at[23], at[40]);    MULADD(at[24], at[39]);    MULADD(at[25], at[38]);    MULADD(at[26], at[37]);    MULADD(at[27], at[36]);    MULADD(at[28], at[35]);    MULADD(at[29], at[34]);    MULADD(at[30], at[33]);    MULADD(at[31], at[32]);
 609   COMBA_STORE(C->dp[31]);
 610   /* 32 */
 611   COMBA_FORWARD;
 612   MULADD(at[1], at[63]);    MULADD(at[2], at[62]);    MULADD(at[3], at[61]);    MULADD(at[4], at[60]);    MULADD(at[5], at[59]);    MULADD(at[6], at[58]);    MULADD(at[7], at[57]);    MULADD(at[8], at[56]);    MULADD(at[9], at[55]);    MULADD(at[10], at[54]);    MULADD(at[11], at[53]);    MULADD(at[12], at[52]);    MULADD(at[13], at[51]);    MULADD(at[14], at[50]);    MULADD(at[15], at[49]);    MULADD(at[16], at[48]);    MULADD(at[17], at[47]);    MULADD(at[18], at[46]);    MULADD(at[19], at[45]);    MULADD(at[20], at[44]);    MULADD(at[21], at[43]);    MULADD(at[22], at[42]);    MULADD(at[23], at[41]);    MULADD(at[24], at[40]);    MULADD(at[25], at[39]);    MULADD(at[26], at[38]);    MULADD(at[27], at[37]);    MULADD(at[28], at[36]);    MULADD(at[29], at[35]);    MULADD(at[30], at[34]);    MULADD(at[31], at[33]);
 613   COMBA_STORE(C->dp[32]);
 614   /* 33 */
 615   COMBA_FORWARD;
 616   MULADD(at[2], at[63]);    MULADD(at[3], at[62]);    MULADD(at[4], at[61]);    MULADD(at[5], at[60]);    MULADD(at[6], at[59]);    MULADD(at[7], at[58]);    MULADD(at[8], at[57]);    MULADD(at[9], at[56]);    MULADD(at[10], at[55]);    MULADD(at[11], at[54]);    MULADD(at[12], at[53]);    MULADD(at[13], at[52]);    MULADD(at[14], at[51]);    MULADD(at[15], at[50]);    MULADD(at[16], at[49]);    MULADD(at[17], at[48]);    MULADD(at[18], at[47]);    MULADD(at[19], at[46]);    MULADD(at[20], at[45]);    MULADD(at[21], at[44]);    MULADD(at[22], at[43]);    MULADD(at[23], at[42]);    MULADD(at[24], at[41]);    MULADD(at[25], at[40]);    MULADD(at[26], at[39]);    MULADD(at[27], at[38]);    MULADD(at[28], at[37]);    MULADD(at[29], at[36]);    MULADD(at[30], at[35]);    MULADD(at[31], at[34]);
 617   COMBA_STORE(C->dp[33]);
 618   /* 34 */
 619   COMBA_FORWARD;
 620   MULADD(at[3], at[63]);    MULADD(at[4], at[62]);    MULADD(at[5], at[61]);    MULADD(at[6], at[60]);    MULADD(at[7], at[59]);    MULADD(at[8], at[58]);    MULADD(at[9], at[57]);    MULADD(at[10], at[56]);    MULADD(at[11], at[55]);    MULADD(at[12], at[54]);    MULADD(at[13], at[53]);    MULADD(at[14], at[52]);    MULADD(at[15], at[51]);    MULADD(at[16], at[50]);    MULADD(at[17], at[49]);    MULADD(at[18], at[48]);    MULADD(at[19], at[47]);    MULADD(at[20], at[46]);    MULADD(at[21], at[45]);    MULADD(at[22], at[44]);    MULADD(at[23], at[43]);    MULADD(at[24], at[42]);    MULADD(at[25], at[41]);    MULADD(at[26], at[40]);    MULADD(at[27], at[39]);    MULADD(at[28], at[38]);    MULADD(at[29], at[37]);    MULADD(at[30], at[36]);    MULADD(at[31], at[35]);
 621   COMBA_STORE(C->dp[34]);
 622   /* 35 */
 623   COMBA_FORWARD;
 624   MULADD(at[4], at[63]);    MULADD(at[5], at[62]);    MULADD(at[6], at[61]);    MULADD(at[7], at[60]);    MULADD(at[8], at[59]);    MULADD(at[9], at[58]);    MULADD(at[10], at[57]);    MULADD(at[11], at[56]);    MULADD(at[12], at[55]);    MULADD(at[13], at[54]);    MULADD(at[14], at[53]);    MULADD(at[15], at[52]);    MULADD(at[16], at[51]);    MULADD(at[17], at[50]);    MULADD(at[18], at[49]);    MULADD(at[19], at[48]);    MULADD(at[20], at[47]);    MULADD(at[21], at[46]);    MULADD(at[22], at[45]);    MULADD(at[23], at[44]);    MULADD(at[24], at[43]);    MULADD(at[25], at[42]);    MULADD(at[26], at[41]);    MULADD(at[27], at[40]);    MULADD(at[28], at[39]);    MULADD(at[29], at[38]);    MULADD(at[30], at[37]);    MULADD(at[31], at[36]);
 625   COMBA_STORE(C->dp[35]);
 626   /* 36 */
 627   COMBA_FORWARD;
 628   MULADD(at[5], at[63]);    MULADD(at[6], at[62]);    MULADD(at[7], at[61]);    MULADD(at[8], at[60]);    MULADD(at[9], at[59]);    MULADD(at[10], at[58]);    MULADD(at[11], at[57]);    MULADD(at[12], at[56]);    MULADD(at[13], at[55]);    MULADD(at[14], at[54]);    MULADD(at[15], at[53]);    MULADD(at[16], at[52]);    MULADD(at[17], at[51]);    MULADD(at[18], at[50]);    MULADD(at[19], at[49]);    MULADD(at[20], at[48]);    MULADD(at[21], at[47]);    MULADD(at[22], at[46]);    MULADD(at[23], at[45]);    MULADD(at[24], at[44]);    MULADD(at[25], at[43]);    MULADD(at[26], at[42]);    MULADD(at[27], at[41]);    MULADD(at[28], at[40]);    MULADD(at[29], at[39]);    MULADD(at[30], at[38]);    MULADD(at[31], at[37]);
 629   COMBA_STORE(C->dp[36]);
 630   /* 37 */
 631   COMBA_FORWARD;
 632   MULADD(at[6], at[63]);    MULADD(at[7], at[62]);    MULADD(at[8], at[61]);    MULADD(at[9], at[60]);    MULADD(at[10], at[59]);    MULADD(at[11], at[58]);    MULADD(at[12], at[57]);    MULADD(at[13], at[56]);    MULADD(at[14], at[55]);    MULADD(at[15], at[54]);    MULADD(at[16], at[53]);    MULADD(at[17], at[52]);    MULADD(at[18], at[51]);    MULADD(at[19], at[50]);    MULADD(at[20], at[49]);    MULADD(at[21], at[48]);    MULADD(at[22], at[47]);    MULADD(at[23], at[46]);    MULADD(at[24], at[45]);    MULADD(at[25], at[44]);    MULADD(at[26], at[43]);    MULADD(at[27], at[42]);    MULADD(at[28], at[41]);    MULADD(at[29], at[40]);    MULADD(at[30], at[39]);    MULADD(at[31], at[38]);
 633   COMBA_STORE(C->dp[37]);
 634   /* 38 */
 635   COMBA_FORWARD;
 636   MULADD(at[7], at[63]);    MULADD(at[8], at[62]);    MULADD(at[9], at[61]);    MULADD(at[10], at[60]);    MULADD(at[11], at[59]);    MULADD(at[12], at[58]);    MULADD(at[13], at[57]);    MULADD(at[14], at[56]);    MULADD(at[15], at[55]);    MULADD(at[16], at[54]);    MULADD(at[17], at[53]);    MULADD(at[18], at[52]);    MULADD(at[19], at[51]);    MULADD(at[20], at[50]);    MULADD(at[21], at[49]);    MULADD(at[22], at[48]);    MULADD(at[23], at[47]);    MULADD(at[24], at[46]);    MULADD(at[25], at[45]);    MULADD(at[26], at[44]);    MULADD(at[27], at[43]);    MULADD(at[28], at[42]);    MULADD(at[29], at[41]);    MULADD(at[30], at[40]);    MULADD(at[31], at[39]);
 637   COMBA_STORE(C->dp[38]);
 638
 639   /* early out at 40 digits, 40*32==1280, or two 640 bit operands */
 640   if (out_size <= 40) { COMBA_STORE2(C->dp[39]); C->used = 40; C->sign = A->sign ^ B->sign; pstm_clamp(C); COMBA_FINI; return PSTM_OKAY; }
 641
 642   /* 39 */
 643   COMBA_FORWARD;
 644   MULADD(at[8], at[63]);    MULADD(at[9], at[62]);    MULADD(at[10], at[61]);    MULADD(at[11], at[60]);    MULADD(at[12], at[59]);    MULADD(at[13], at[58]);    MULADD(at[14], at[57]);    MULADD(at[15], at[56]);    MULADD(at[16], at[55]);    MULADD(at[17], at[54]);    MULADD(at[18], at[53]);    MULADD(at[19], at[52]);    MULADD(at[20], at[51]);    MULADD(at[21], at[50]);    MULADD(at[22], at[49]);    MULADD(at[23], at[48]);    MULADD(at[24], at[47]);    MULADD(at[25], at[46]);    MULADD(at[26], at[45]);    MULADD(at[27], at[44]);    MULADD(at[28], at[43]);    MULADD(at[29], at[42]);    MULADD(at[30], at[41]);    MULADD(at[31], at[40]);
 645   COMBA_STORE(C->dp[39]);
 646   /* 40 */
 647   COMBA_FORWARD;
 648   MULADD(at[9], at[63]);    MULADD(at[10], at[62]);    MULADD(at[11], at[61]);    MULADD(at[12], at[60]);    MULADD(at[13], at[59]);    MULADD(at[14], at[58]);    MULADD(at[15], at[57]);    MULADD(at[16], at[56]);    MULADD(at[17], at[55]);    MULADD(at[18], at[54]);    MULADD(at[19], at[53]);    MULADD(at[20], at[52]);    MULADD(at[21], at[51]);    MULADD(at[22], at[50]);    MULADD(at[23], at[49]);    MULADD(at[24], at[48]);    MULADD(at[25], at[47]);    MULADD(at[26], at[46]);    MULADD(at[27], at[45]);    MULADD(at[28], at[44]);    MULADD(at[29], at[43]);    MULADD(at[30], at[42]);    MULADD(at[31], at[41]);
 649   COMBA_STORE(C->dp[40]);
 650   /* 41 */
 651   COMBA_FORWARD;
 652   MULADD(at[10], at[63]);    MULADD(at[11], at[62]);    MULADD(at[12], at[61]);    MULADD(at[13], at[60]);    MULADD(at[14], at[59]);    MULADD(at[15], at[58]);    MULADD(at[16], at[57]);    MULADD(at[17], at[56]);    MULADD(at[18], at[55]);    MULADD(at[19], at[54]);    MULADD(at[20], at[53]);    MULADD(at[21], at[52]);    MULADD(at[22], at[51]);    MULADD(at[23], at[50]);    MULADD(at[24], at[49]);    MULADD(at[25], at[48]);    MULADD(at[26], at[47]);    MULADD(at[27], at[46]);    MULADD(at[28], at[45]);    MULADD(at[29], at[44]);    MULADD(at[30], at[43]);    MULADD(at[31], at[42]);
 653   COMBA_STORE(C->dp[41]);
 654   /* 42 */
 655   COMBA_FORWARD;
 656   MULADD(at[11], at[63]);    MULADD(at[12], at[62]);    MULADD(at[13], at[61]);    MULADD(at[14], at[60]);    MULADD(at[15], at[59]);    MULADD(at[16], at[58]);    MULADD(at[17], at[57]);    MULADD(at[18], at[56]);    MULADD(at[19], at[55]);    MULADD(at[20], at[54]);    MULADD(at[21], at[53]);    MULADD(at[22], at[52]);    MULADD(at[23], at[51]);    MULADD(at[24], at[50]);    MULADD(at[25], at[49]);    MULADD(at[26], at[48]);    MULADD(at[27], at[47]);    MULADD(at[28], at[46]);    MULADD(at[29], at[45]);    MULADD(at[30], at[44]);    MULADD(at[31], at[43]);
 657   COMBA_STORE(C->dp[42]);
 658   /* 43 */
 659   COMBA_FORWARD;
 660   MULADD(at[12], at[63]);    MULADD(at[13], at[62]);    MULADD(at[14], at[61]);    MULADD(at[15], at[60]);    MULADD(at[16], at[59]);    MULADD(at[17], at[58]);    MULADD(at[18], at[57]);    MULADD(at[19], at[56]);    MULADD(at[20], at[55]);    MULADD(at[21], at[54]);    MULADD(at[22], at[53]);    MULADD(at[23], at[52]);    MULADD(at[24], at[51]);    MULADD(at[25], at[50]);    MULADD(at[26], at[49]);    MULADD(at[27], at[48]);    MULADD(at[28], at[47]);    MULADD(at[29], at[46]);    MULADD(at[30], at[45]);    MULADD(at[31], at[44]);
 661   COMBA_STORE(C->dp[43]);
 662   /* 44 */
 663   COMBA_FORWARD;
 664   MULADD(at[13], at[63]);    MULADD(at[14], at[62]);    MULADD(at[15], at[61]);    MULADD(at[16], at[60]);    MULADD(at[17], at[59]);    MULADD(at[18], at[58]);    MULADD(at[19], at[57]);    MULADD(at[20], at[56]);    MULADD(at[21], at[55]);    MULADD(at[22], at[54]);    MULADD(at[23], at[53]);    MULADD(at[24], at[52]);    MULADD(at[25], at[51]);    MULADD(at[26], at[50]);    MULADD(at[27], at[49]);    MULADD(at[28], at[48]);    MULADD(at[29], at[47]);    MULADD(at[30], at[46]);    MULADD(at[31], at[45]);
 665   COMBA_STORE(C->dp[44]);
 666   /* 45 */
 667   COMBA_FORWARD;
 668   MULADD(at[14], at[63]);    MULADD(at[15], at[62]);    MULADD(at[16], at[61]);    MULADD(at[17], at[60]);    MULADD(at[18], at[59]);    MULADD(at[19], at[58]);    MULADD(at[20], at[57]);    MULADD(at[21], at[56]);    MULADD(at[22], at[55]);    MULADD(at[23], at[54]);    MULADD(at[24], at[53]);    MULADD(at[25], at[52]);    MULADD(at[26], at[51]);    MULADD(at[27], at[50]);    MULADD(at[28], at[49]);    MULADD(at[29], at[48]);    MULADD(at[30], at[47]);    MULADD(at[31], at[46]);
 669   COMBA_STORE(C->dp[45]);
 670   /* 46 */
 671   COMBA_FORWARD;
 672   MULADD(at[15], at[63]);    MULADD(at[16], at[62]);    MULADD(at[17], at[61]);    MULADD(at[18], at[60]);    MULADD(at[19], at[59]);    MULADD(at[20], at[58]);    MULADD(at[21], at[57]);    MULADD(at[22], at[56]);    MULADD(at[23], at[55]);    MULADD(at[24], at[54]);    MULADD(at[25], at[53]);    MULADD(at[26], at[52]);    MULADD(at[27], at[51]);    MULADD(at[28], at[50]);    MULADD(at[29], at[49]);    MULADD(at[30], at[48]);    MULADD(at[31], at[47]);
 673   COMBA_STORE(C->dp[46]);
 674
 675   /* early out at 48 digits, 48*32==1536, or two 768 bit operands */
 676   if (out_size <= 48) { COMBA_STORE2(C->dp[47]); C->used = 48; C->sign = A->sign ^ B->sign; pstm_clamp(C); COMBA_FINI; return PSTM_OKAY; }
 677
 678   /* 47 */
 679   COMBA_FORWARD;
 680   MULADD(at[16], at[63]);    MULADD(at[17], at[62]);    MULADD(at[18], at[61]);    MULADD(at[19], at[60]);    MULADD(at[20], at[59]);    MULADD(at[21], at[58]);    MULADD(at[22], at[57]);    MULADD(at[23], at[56]);    MULADD(at[24], at[55]);    MULADD(at[25], at[54]);    MULADD(at[26], at[53]);    MULADD(at[27], at[52]);    MULADD(at[28], at[51]);    MULADD(at[29], at[50]);    MULADD(at[30], at[49]);    MULADD(at[31], at[48]);
 681   COMBA_STORE(C->dp[47]);
 682   /* 48 */
 683   COMBA_FORWARD;
 684   MULADD(at[17], at[63]);    MULADD(at[18], at[62]);    MULADD(at[19], at[61]);    MULADD(at[20], at[60]);    MULADD(at[21], at[59]);    MULADD(at[22], at[58]);    MULADD(at[23], at[57]);    MULADD(at[24], at[56]);    MULADD(at[25], at[55]);    MULADD(at[26], at[54]);    MULADD(at[27], at[53]);    MULADD(at[28], at[52]);    MULADD(at[29], at[51]);    MULADD(at[30], at[50]);    MULADD(at[31], at[49]);
 685   COMBA_STORE(C->dp[48]);
 686   /* 49 */
 687   COMBA_FORWARD;
 688   MULADD(at[18], at[63]);    MULADD(at[19], at[62]);    MULADD(at[20], at[61]);    MULADD(at[21], at[60]);    MULADD(at[22], at[59]);    MULADD(at[23], at[58]);    MULADD(at[24], at[57]);    MULADD(at[25], at[56]);    MULADD(at[26], at[55]);    MULADD(at[27], at[54]);    MULADD(at[28], at[53]);    MULADD(at[29], at[52]);    MULADD(at[30], at[51]);    MULADD(at[31], at[50]);
 689   COMBA_STORE(C->dp[49]);
 690   /* 50 */
 691   COMBA_FORWARD;
 692   MULADD(at[19], at[63]);    MULADD(at[20], at[62]);    MULADD(at[21], at[61]);    MULADD(at[22], at[60]);    MULADD(at[23], at[59]);    MULADD(at[24], at[58]);    MULADD(at[25], at[57]);    MULADD(at[26], at[56]);    MULADD(at[27], at[55]);    MULADD(at[28], at[54]);    MULADD(at[29], at[53]);    MULADD(at[30], at[52]);    MULADD(at[31], at[51]);
 693   COMBA_STORE(C->dp[50]);
 694   /* 51 */
 695   COMBA_FORWARD;
 696   MULADD(at[20], at[63]);    MULADD(at[21], at[62]);    MULADD(at[22], at[61]);    MULADD(at[23], at[60]);    MULADD(at[24], at[59]);    MULADD(at[25], at[58]);    MULADD(at[26], at[57]);    MULADD(at[27], at[56]);    MULADD(at[28], at[55]);    MULADD(at[29], at[54]);    MULADD(at[30], at[53]);    MULADD(at[31], at[52]);
 697   COMBA_STORE(C->dp[51]);
 698   /* 52 */
 699   COMBA_FORWARD;
 700   MULADD(at[21], at[63]);    MULADD(at[22], at[62]);    MULADD(at[23], at[61]);    MULADD(at[24], at[60]);    MULADD(at[25], at[59]);    MULADD(at[26], at[58]);    MULADD(at[27], at[57]);    MULADD(at[28], at[56]);    MULADD(at[29], at[55]);    MULADD(at[30], at[54]);    MULADD(at[31], at[53]);
 701   COMBA_STORE(C->dp[52]);
 702   /* 53 */
 703   COMBA_FORWARD;
 704   MULADD(at[22], at[63]);    MULADD(at[23], at[62]);    MULADD(at[24], at[61]);    MULADD(at[25], at[60]);    MULADD(at[26], at[59]);    MULADD(at[27], at[58]);    MULADD(at[28], at[57]);    MULADD(at[29], at[56]);    MULADD(at[30], at[55]);    MULADD(at[31], at[54]);
 705   COMBA_STORE(C->dp[53]);
 706   /* 54 */
 707   COMBA_FORWARD;
 708   MULADD(at[23], at[63]);    MULADD(at[24], at[62]);    MULADD(at[25], at[61]);    MULADD(at[26], at[60]);    MULADD(at[27], at[59]);    MULADD(at[28], at[58]);    MULADD(at[29], at[57]);    MULADD(at[30], at[56]);    MULADD(at[31], at[55]);
 709   COMBA_STORE(C->dp[54]);
 710
 711   /* early out at 56 digits, 56*32==1792, or two 896 bit operands */
 712   if (out_size <= 56) { COMBA_STORE2(C->dp[55]); C->used = 56; C->sign = A->sign ^ B->sign; pstm_clamp(C); COMBA_FINI; return PSTM_OKAY; }
 713
 714   /* 55 */
 715   COMBA_FORWARD;
 716   MULADD(at[24], at[63]);    MULADD(at[25], at[62]);    MULADD(at[26], at[61]);    MULADD(at[27], at[60]);    MULADD(at[28], at[59]);    MULADD(at[29], at[58]);    MULADD(at[30], at[57]);    MULADD(at[31], at[56]);
 717   COMBA_STORE(C->dp[55]);
 718   /* 56 */
 719   COMBA_FORWARD;
 720   MULADD(at[25], at[63]);    MULADD(at[26], at[62]);    MULADD(at[27], at[61]);    MULADD(at[28], at[60]);    MULADD(at[29], at[59]);    MULADD(at[30], at[58]);    MULADD(at[31], at[57]);
 721   COMBA_STORE(C->dp[56]);
 722   /* 57 */
 723   COMBA_FORWARD;
 724   MULADD(at[26], at[63]);    MULADD(at[27], at[62]);    MULADD(at[28], at[61]);    MULADD(at[29], at[60]);    MULADD(at[30], at[59]);    MULADD(at[31], at[58]);
 725   COMBA_STORE(C->dp[57]);
 726   /* 58 */
 727   COMBA_FORWARD;
 728   MULADD(at[27], at[63]);    MULADD(at[28], at[62]);    MULADD(at[29], at[61]);    MULADD(at[30], at[60]);    MULADD(at[31], at[59]);
 729   COMBA_STORE(C->dp[58]);
 730   /* 59 */
 731   COMBA_FORWARD;
 732   MULADD(at[28], at[63]);    MULADD(at[29], at[62]);    MULADD(at[30], at[61]);    MULADD(at[31], at[60]);
 733   COMBA_STORE(C->dp[59]);
 734   /* 60 */
 735   COMBA_FORWARD;
 736   MULADD(at[29], at[63]);    MULADD(at[30], at[62]);    MULADD(at[31], at[61]);
 737   COMBA_STORE(C->dp[60]);
 738   /* 61 */
 739   COMBA_FORWARD;
 740   MULADD(at[30], at[63]);    MULADD(at[31], at[62]);
 741   COMBA_STORE(C->dp[61]);
 742   /* 62 */
 743   COMBA_FORWARD;
 744   MULADD(at[31], at[63]);
 745   COMBA_STORE(C->dp[62]);
 746   COMBA_STORE2(C->dp[63]);
 747   C->used = 64;
 748   C->sign = A->sign ^ B->sign;
 749   pstm_clamp(C);
 750   COMBA_FINI;
 751        return PSTM_OKAY;
 752}
 753#endif /* USE_2048_KEY_SPEED_OPTIMIZATIONS */
 754
 755/******************************************************************************/
 756
 757int32 FAST_FUNC pstm_mul_comba(psPool_t *pool, pstm_int *A, pstm_int *B, pstm_int *C,
 758                        pstm_digit *paD, uint32 paDlen)
 759{
 760#ifdef USE_1024_KEY_SPEED_OPTIMIZATIONS
 761        if (A->used == 16 && B->used == 16) {
 762                return pstm_mul_comba16(A, B, C);
 763        } else {
 764#ifdef USE_2048_KEY_SPEED_OPTIMIZATIONS
 765                if (A->used == 32 && B->used == 32) {
 766                        return pstm_mul_comba32(A, B, C);
 767                }
 768#endif /* USE_2048_KEY_SPEED_OPTIMIZATIONS */
 769                return pstm_mul_comba_gen(pool, A, B, C, paD, paDlen);
 770        }
 771#else
 772#ifdef USE_2048_KEY_SPEED_OPTIMIZATIONS
 773        if (A->used == 32 && B->used == 32) {
 774                return pstm_mul_comba32(A, B, C);
 775        }
 776#endif /* USE_2048_KEY_SPEED_OPTIMIZATIONS */
 777        return pstm_mul_comba_gen(pool, A, B, C, paD, paDlen);
 778#endif
 779}
 780
 781#endif /* !DISABLE_PSTM */
 782/******************************************************************************/
 783