LCOV - code coverage report
Current view: top level - lib/mpi - mpih-mul.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 108 204 52.9 %
Date: 2022-04-01 14:17:54 Functions: 6 7 85.7 %
Branches: 55 140 39.3 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /* mpihelp-mul.c  -  MPI helper functions
       3                 :            :  * Copyright (C) 1994, 1996, 1998, 1999,
       4                 :            :  *               2000 Free Software Foundation, Inc.
       5                 :            :  *
       6                 :            :  * This file is part of GnuPG.
       7                 :            :  *
       8                 :            :  * Note: This code is heavily based on the GNU MP Library.
       9                 :            :  *       Actually it's the same code with only minor changes in the
      10                 :            :  *       way the data is stored; this is to support the abstraction
      11                 :            :  *       of an optional secure memory allocation which may be used
      12                 :            :  *       to avoid revealing of sensitive data due to paging etc.
      13                 :            :  *       The GNU MP Library itself is published under the LGPL;
      14                 :            :  *       however I decided to publish this code under the plain GPL.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <linux/string.h>
      18                 :            : #include "mpi-internal.h"
      19                 :            : #include "longlong.h"
      20                 :            : 
      21                 :            : #define MPN_MUL_N_RECURSE(prodp, up, vp, size, tspace)          \
      22                 :            :         do {                                                    \
      23                 :            :                 if ((size) < KARATSUBA_THRESHOLD)            \
      24                 :            :                         mul_n_basecase(prodp, up, vp, size);    \
      25                 :            :                 else                                            \
      26                 :            :                         mul_n(prodp, up, vp, size, tspace);     \
      27                 :            :         } while (0);
      28                 :            : 
      29                 :            : #define MPN_SQR_N_RECURSE(prodp, up, size, tspace)              \
      30                 :            :         do {                                                    \
      31                 :            :                 if ((size) < KARATSUBA_THRESHOLD)            \
      32                 :            :                         mpih_sqr_n_basecase(prodp, up, size);   \
      33                 :            :                 else                                            \
      34                 :            :                         mpih_sqr_n(prodp, up, size, tspace);    \
      35                 :            :         } while (0);
      36                 :            : 
      37                 :            : /* Multiply the natural numbers u (pointed to by UP) and v (pointed to by VP),
      38                 :            :  * both with SIZE limbs, and store the result at PRODP.  2 * SIZE limbs are
      39                 :            :  * always stored.  Return the most significant limb.
      40                 :            :  *
      41                 :            :  * Argument constraints:
      42                 :            :  * 1. PRODP != UP and PRODP != VP, i.e. the destination
      43                 :            :  *    must be distinct from the multiplier and the multiplicand.
      44                 :            :  *
      45                 :            :  *
      46                 :            :  * Handle simple cases with traditional multiplication.
      47                 :            :  *
      48                 :            :  * This is the most critical code of multiplication.  All multiplies rely
      49                 :            :  * on this, both small and huge.  Small ones arrive here immediately.  Huge
      50                 :            :  * ones arrive here as this is the base case for Karatsuba's recursive
      51                 :            :  * algorithm below.
      52                 :            :  */
      53                 :            : 
      54                 :            : static mpi_limb_t
      55                 :         99 : mul_n_basecase(mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size)
      56                 :            : {
      57                 :         99 :         mpi_size_t i;
      58                 :         99 :         mpi_limb_t cy;
      59                 :         99 :         mpi_limb_t v_limb;
      60                 :            : 
      61                 :            :         /* Multiply by the first limb in V separately, as the result can be
      62                 :            :          * stored (not added) to PROD.  We also avoid a loop for zeroing.  */
      63                 :         99 :         v_limb = vp[0];
      64         [ -  + ]:         99 :         if (v_limb <= 1) {
      65         [ #  # ]:          0 :                 if (v_limb == 1)
      66         [ #  # ]:          0 :                         MPN_COPY(prodp, up, size);
      67                 :            :                 else
      68         [ #  # ]:          0 :                         MPN_ZERO(prodp, size);
      69                 :            :                 cy = 0;
      70                 :            :         } else
      71                 :         99 :                 cy = mpihelp_mul_1(prodp, up, size, v_limb);
      72                 :            : 
      73                 :         99 :         prodp[size] = cy;
      74                 :         99 :         prodp++;
      75                 :            : 
      76                 :            :         /* For each iteration in the outer loop, multiply one limb from
      77                 :            :          * U with one limb from V, and add it to PROD.  */
      78         [ +  + ]:        792 :         for (i = 1; i < size; i++) {
      79                 :        693 :                 v_limb = vp[i];
      80         [ -  + ]:        693 :                 if (v_limb <= 1) {
      81                 :          0 :                         cy = 0;
      82         [ #  # ]:          0 :                         if (v_limb == 1)
      83                 :          0 :                                 cy = mpihelp_add_n(prodp, prodp, up, size);
      84                 :            :                 } else
      85                 :        693 :                         cy = mpihelp_addmul_1(prodp, up, size, v_limb);
      86                 :            : 
      87                 :        693 :                 prodp[size] = cy;
      88                 :        693 :                 prodp++;
      89                 :            :         }
      90                 :            : 
      91                 :         99 :         return cy;
      92                 :            : }
      93                 :            : 
      94                 :            : static void
      95                 :         44 : mul_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp,
      96                 :            :                 mpi_size_t size, mpi_ptr_t tspace)
      97                 :            : {
      98         [ -  + ]:         44 :         if (size & 1) {
      99                 :            :                 /* The size is odd, and the code below doesn't handle that.
     100                 :            :                  * Multiply the least significant (size - 1) limbs with a recursive
     101                 :            :                  * call, and handle the most significant limb of S1 and S2
     102                 :            :                  * separately.
     103                 :            :                  * A slightly faster way to do this would be to make the Karatsuba
     104                 :            :                  * code below behave as if the size were even, and let it check for
     105                 :            :                  * odd size in the end.  I.e., in essence move this code to the end.
     106                 :            :                  * Doing so would save us a recursive call, and potentially make the
     107                 :            :                  * stack grow a lot less.
     108                 :            :                  */
     109                 :          0 :                 mpi_size_t esize = size - 1;    /* even size */
     110                 :          0 :                 mpi_limb_t cy_limb;
     111                 :            : 
     112         [ #  # ]:          0 :                 MPN_MUL_N_RECURSE(prodp, up, vp, esize, tspace);
     113                 :          0 :                 cy_limb = mpihelp_addmul_1(prodp + esize, up, esize, vp[esize]);
     114                 :          0 :                 prodp[esize + esize] = cy_limb;
     115                 :          0 :                 cy_limb = mpihelp_addmul_1(prodp + esize, vp, size, up[esize]);
     116                 :          0 :                 prodp[esize + size] = cy_limb;
     117                 :            :         } else {
     118                 :            :                 /* Anatolij Alekseevich Karatsuba's divide-and-conquer algorithm.
     119                 :            :                  *
     120                 :            :                  * Split U in two pieces, U1 and U0, such that
     121                 :            :                  * U = U0 + U1*(B**n),
     122                 :            :                  * and V in V1 and V0, such that
     123                 :            :                  * V = V0 + V1*(B**n).
     124                 :            :                  *
     125                 :            :                  * UV is then computed recursively using the identity
     126                 :            :                  *
     127                 :            :                  *        2n   n          n                     n
     128                 :            :                  * UV = (B  + B )U V  +  B (U -U )(V -V )  +  (B + 1)U V
     129                 :            :                  *                1 1        1  0   0  1              0 0
     130                 :            :                  *
     131                 :            :                  * Where B = 2**BITS_PER_MP_LIMB.
     132                 :            :                  */
     133                 :         44 :                 mpi_size_t hsize = size >> 1;
     134                 :         44 :                 mpi_limb_t cy;
     135                 :         44 :                 int negflg;
     136                 :            : 
     137                 :            :                 /* Product H.      ________________  ________________
     138                 :            :                  *                |_____U1 x V1____||____U0 x V0_____|
     139                 :            :                  * Put result in upper part of PROD and pass low part of TSPACE
     140                 :            :                  * as new TSPACE.
     141                 :            :                  */
     142         [ +  + ]:         44 :                 MPN_MUL_N_RECURSE(prodp + size, up + hsize, vp + hsize, hsize,
     143                 :         44 :                                   tspace);
     144                 :            : 
     145                 :            :                 /* Product M.      ________________
     146                 :            :                  *                |_(U1-U0)(V0-V1)_|
     147                 :            :                  */
     148         [ +  + ]:         44 :                 if (mpihelp_cmp(up + hsize, up, hsize) >= 0) {
     149                 :         11 :                         mpihelp_sub_n(prodp, up + hsize, up, hsize);
     150                 :         11 :                         negflg = 0;
     151                 :            :                 } else {
     152                 :         33 :                         mpihelp_sub_n(prodp, up, up + hsize, hsize);
     153                 :         33 :                         negflg = 1;
     154                 :            :                 }
     155         [ +  + ]:         44 :                 if (mpihelp_cmp(vp + hsize, vp, hsize) >= 0) {
     156                 :         33 :                         mpihelp_sub_n(prodp + hsize, vp + hsize, vp, hsize);
     157                 :         33 :                         negflg ^= 1;
     158                 :            :                 } else {
     159                 :         11 :                         mpihelp_sub_n(prodp + hsize, vp, vp + hsize, hsize);
     160                 :            :                         /* No change of NEGFLG.  */
     161                 :            :                 }
     162                 :            :                 /* Read temporary operands from low part of PROD.
     163                 :            :                  * Put result in low part of TSPACE using upper part of TSPACE
     164                 :            :                  * as new TSPACE.
     165                 :            :                  */
     166         [ +  + ]:         44 :                 MPN_MUL_N_RECURSE(tspace, prodp, prodp + hsize, hsize,
     167                 :            :                                   tspace + size);
     168                 :            : 
     169                 :            :                 /* Add/copy product H. */
     170         [ +  + ]:        484 :                 MPN_COPY(prodp + hsize, prodp + size, hsize);
     171                 :         44 :                 cy = mpihelp_add_n(prodp + size, prodp + size,
     172                 :         44 :                                    prodp + size + hsize, hsize);
     173                 :            : 
     174                 :            :                 /* Add product M (if NEGFLG M is a negative number) */
     175         [ +  + ]:         44 :                 if (negflg)
     176                 :         22 :                         cy -=
     177                 :         22 :                             mpihelp_sub_n(prodp + hsize, prodp + hsize, tspace,
     178                 :            :                                           size);
     179                 :            :                 else
     180                 :         22 :                         cy +=
     181                 :         22 :                             mpihelp_add_n(prodp + hsize, prodp + hsize, tspace,
     182                 :            :                                           size);
     183                 :            : 
     184                 :            :                 /* Product L.      ________________  ________________
     185                 :            :                  *                |________________||____U0 x V0_____|
     186                 :            :                  * Read temporary operands from low part of PROD.
     187                 :            :                  * Put result in low part of TSPACE using upper part of TSPACE
     188                 :            :                  * as new TSPACE.
     189                 :            :                  */
     190         [ +  + ]:         44 :                 MPN_MUL_N_RECURSE(tspace, up, vp, hsize, tspace + size);
     191                 :            : 
     192                 :            :                 /* Add/copy Product L (twice) */
     193                 :            : 
     194                 :         44 :                 cy += mpihelp_add_n(prodp + hsize, prodp + hsize, tspace, size);
     195         [ +  + ]:         44 :                 if (cy)
     196                 :         11 :                         mpihelp_add_1(prodp + hsize + size,
     197                 :            :                                       prodp + hsize + size, hsize, cy);
     198                 :            : 
     199         [ +  + ]:        484 :                 MPN_COPY(prodp, tspace, hsize);
     200                 :         44 :                 cy = mpihelp_add_n(prodp + hsize, prodp + hsize, tspace + hsize,
     201                 :            :                                    hsize);
     202         [ +  + ]:         44 :                 if (cy)
     203                 :         22 :                         mpihelp_add_1(prodp + size, prodp + size, size, 1);
     204                 :            :         }
     205                 :         44 : }
     206                 :            : 
     207                 :       1584 : void mpih_sqr_n_basecase(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size)
     208                 :            : {
     209                 :       1584 :         mpi_size_t i;
     210                 :       1584 :         mpi_limb_t cy_limb;
     211                 :       1584 :         mpi_limb_t v_limb;
     212                 :            : 
     213                 :            :         /* Multiply by the first limb in V separately, as the result can be
     214                 :            :          * stored (not added) to PROD.  We also avoid a loop for zeroing.  */
     215                 :       1584 :         v_limb = up[0];
     216         [ -  + ]:       1584 :         if (v_limb <= 1) {
     217         [ #  # ]:          0 :                 if (v_limb == 1)
     218         [ #  # ]:          0 :                         MPN_COPY(prodp, up, size);
     219                 :            :                 else
     220         [ #  # ]:          0 :                         MPN_ZERO(prodp, size);
     221                 :            :                 cy_limb = 0;
     222                 :            :         } else
     223                 :       1584 :                 cy_limb = mpihelp_mul_1(prodp, up, size, v_limb);
     224                 :            : 
     225                 :       1584 :         prodp[size] = cy_limb;
     226                 :       1584 :         prodp++;
     227                 :            : 
     228                 :            :         /* For each iteration in the outer loop, multiply one limb from
     229                 :            :          * U with one limb from V, and add it to PROD.  */
     230         [ +  + ]:      12672 :         for (i = 1; i < size; i++) {
     231                 :      11088 :                 v_limb = up[i];
     232         [ -  + ]:      11088 :                 if (v_limb <= 1) {
     233                 :          0 :                         cy_limb = 0;
     234         [ #  # ]:          0 :                         if (v_limb == 1)
     235                 :          0 :                                 cy_limb = mpihelp_add_n(prodp, prodp, up, size);
     236                 :            :                 } else
     237                 :      11088 :                         cy_limb = mpihelp_addmul_1(prodp, up, size, v_limb);
     238                 :            : 
     239                 :      11088 :                 prodp[size] = cy_limb;
     240                 :      11088 :                 prodp++;
     241                 :            :         }
     242                 :       1584 : }
     243                 :            : 
     244                 :            : void
     245                 :        704 : mpih_sqr_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size, mpi_ptr_t tspace)
     246                 :            : {
     247         [ -  + ]:        704 :         if (size & 1) {
     248                 :            :                 /* The size is odd, and the code below doesn't handle that.
     249                 :            :                  * Multiply the least significant (size - 1) limbs with a recursive
     250                 :            :                  * call, and handle the most significant limb of S1 and S2
     251                 :            :                  * separately.
     252                 :            :                  * A slightly faster way to do this would be to make the Karatsuba
     253                 :            :                  * code below behave as if the size were even, and let it check for
     254                 :            :                  * odd size in the end.  I.e., in essence move this code to the end.
     255                 :            :                  * Doing so would save us a recursive call, and potentially make the
     256                 :            :                  * stack grow a lot less.
     257                 :            :                  */
     258                 :          0 :                 mpi_size_t esize = size - 1;    /* even size */
     259                 :          0 :                 mpi_limb_t cy_limb;
     260                 :            : 
     261         [ #  # ]:          0 :                 MPN_SQR_N_RECURSE(prodp, up, esize, tspace);
     262                 :          0 :                 cy_limb = mpihelp_addmul_1(prodp + esize, up, esize, up[esize]);
     263                 :          0 :                 prodp[esize + esize] = cy_limb;
     264                 :          0 :                 cy_limb = mpihelp_addmul_1(prodp + esize, up, size, up[esize]);
     265                 :            : 
     266                 :          0 :                 prodp[esize + size] = cy_limb;
     267                 :            :         } else {
     268                 :        704 :                 mpi_size_t hsize = size >> 1;
     269                 :        704 :                 mpi_limb_t cy;
     270                 :            : 
     271                 :            :                 /* Product H.      ________________  ________________
     272                 :            :                  *                |_____U1 x U1____||____U0 x U0_____|
     273                 :            :                  * Put result in upper part of PROD and pass low part of TSPACE
     274                 :            :                  * as new TSPACE.
     275                 :            :                  */
     276         [ +  + ]:        704 :                 MPN_SQR_N_RECURSE(prodp + size, up + hsize, hsize, tspace);
     277                 :            : 
     278                 :            :                 /* Product M.      ________________
     279                 :            :                  *                |_(U1-U0)(U0-U1)_|
     280                 :            :                  */
     281         [ +  + ]:        704 :                 if (mpihelp_cmp(up + hsize, up, hsize) >= 0)
     282                 :        275 :                         mpihelp_sub_n(prodp, up + hsize, up, hsize);
     283                 :            :                 else
     284                 :        429 :                         mpihelp_sub_n(prodp, up, up + hsize, hsize);
     285                 :            : 
     286                 :            :                 /* Read temporary operands from low part of PROD.
     287                 :            :                  * Put result in low part of TSPACE using upper part of TSPACE
     288                 :            :                  * as new TSPACE.  */
     289         [ +  + ]:        704 :                 MPN_SQR_N_RECURSE(tspace, prodp, hsize, tspace + size);
     290                 :            : 
     291                 :            :                 /* Add/copy product H  */
     292         [ +  + ]:       7744 :                 MPN_COPY(prodp + hsize, prodp + size, hsize);
     293                 :        704 :                 cy = mpihelp_add_n(prodp + size, prodp + size,
     294                 :        704 :                                    prodp + size + hsize, hsize);
     295                 :            : 
     296                 :            :                 /* Add product M (if NEGFLG M is a negative number).  */
     297                 :        704 :                 cy -= mpihelp_sub_n(prodp + hsize, prodp + hsize, tspace, size);
     298                 :            : 
     299                 :            :                 /* Product L.      ________________  ________________
     300                 :            :                  *                |________________||____U0 x U0_____|
     301                 :            :                  * Read temporary operands from low part of PROD.
     302                 :            :                  * Put result in low part of TSPACE using upper part of TSPACE
     303                 :            :                  * as new TSPACE.  */
     304         [ +  + ]:        704 :                 MPN_SQR_N_RECURSE(tspace, up, hsize, tspace + size);
     305                 :            : 
     306                 :            :                 /* Add/copy Product L (twice).  */
     307                 :        704 :                 cy += mpihelp_add_n(prodp + hsize, prodp + hsize, tspace, size);
     308         [ +  + ]:        704 :                 if (cy)
     309                 :        286 :                         mpihelp_add_1(prodp + hsize + size,
     310                 :            :                                       prodp + hsize + size, hsize, cy);
     311                 :            : 
     312         [ +  + ]:       7744 :                 MPN_COPY(prodp, tspace, hsize);
     313                 :        704 :                 cy = mpihelp_add_n(prodp + hsize, prodp + hsize, tspace + hsize,
     314                 :            :                                    hsize);
     315         [ +  + ]:        704 :                 if (cy)
     316                 :        275 :                         mpihelp_add_1(prodp + size, prodp + size, size, 1);
     317                 :            :         }
     318                 :        704 : }
     319                 :            : 
     320                 :            : int
     321                 :         11 : mpihelp_mul_karatsuba_case(mpi_ptr_t prodp,
     322                 :            :                            mpi_ptr_t up, mpi_size_t usize,
     323                 :            :                            mpi_ptr_t vp, mpi_size_t vsize,
     324                 :            :                            struct karatsuba_ctx *ctx)
     325                 :            : {
     326                 :         11 :         mpi_limb_t cy;
     327                 :            : 
     328   [ -  +  -  - ]:         11 :         if (!ctx->tspace || ctx->tspace_size < vsize) {
     329         [ -  + ]:         11 :                 if (ctx->tspace)
     330                 :          0 :                         mpi_free_limb_space(ctx->tspace);
     331                 :         11 :                 ctx->tspace = mpi_alloc_limb_space(2 * vsize);
     332         [ +  - ]:         11 :                 if (!ctx->tspace)
     333                 :            :                         return -ENOMEM;
     334                 :         11 :                 ctx->tspace_size = vsize;
     335                 :            :         }
     336                 :            : 
     337         [ -  + ]:         11 :         MPN_MUL_N_RECURSE(prodp, up, vp, vsize, ctx->tspace);
     338                 :            : 
     339                 :         11 :         prodp += vsize;
     340                 :         11 :         up += vsize;
     341                 :         11 :         usize -= vsize;
     342         [ -  + ]:         11 :         if (usize >= vsize) {
     343   [ #  #  #  # ]:          0 :                 if (!ctx->tp || ctx->tp_size < vsize) {
     344         [ #  # ]:          0 :                         if (ctx->tp)
     345                 :          0 :                                 mpi_free_limb_space(ctx->tp);
     346                 :          0 :                         ctx->tp = mpi_alloc_limb_space(2 * vsize);
     347         [ #  # ]:          0 :                         if (!ctx->tp) {
     348         [ #  # ]:          0 :                                 if (ctx->tspace)
     349                 :          0 :                                         mpi_free_limb_space(ctx->tspace);
     350                 :          0 :                                 ctx->tspace = NULL;
     351                 :          0 :                                 return -ENOMEM;
     352                 :            :                         }
     353                 :          0 :                         ctx->tp_size = vsize;
     354                 :            :                 }
     355                 :            : 
     356                 :          0 :                 do {
     357         [ #  # ]:          0 :                         MPN_MUL_N_RECURSE(ctx->tp, up, vp, vsize, ctx->tspace);
     358                 :          0 :                         cy = mpihelp_add_n(prodp, prodp, ctx->tp, vsize);
     359                 :          0 :                         mpihelp_add_1(prodp + vsize, ctx->tp + vsize, vsize,
     360                 :            :                                       cy);
     361                 :          0 :                         prodp += vsize;
     362                 :          0 :                         up += vsize;
     363                 :          0 :                         usize -= vsize;
     364         [ #  # ]:          0 :                 } while (usize >= vsize);
     365                 :            :         }
     366                 :            : 
     367         [ -  + ]:         11 :         if (usize) {
     368         [ #  # ]:          0 :                 if (usize < KARATSUBA_THRESHOLD) {
     369                 :          0 :                         mpi_limb_t tmp;
     370         [ #  # ]:          0 :                         if (mpihelp_mul(ctx->tspace, vp, vsize, up, usize, &tmp)
     371                 :            :                             < 0)
     372                 :          0 :                                 return -ENOMEM;
     373                 :            :                 } else {
     374         [ #  # ]:          0 :                         if (!ctx->next) {
     375                 :          0 :                                 ctx->next = kzalloc(sizeof *ctx, GFP_KERNEL);
     376         [ #  # ]:          0 :                                 if (!ctx->next)
     377                 :            :                                         return -ENOMEM;
     378                 :            :                         }
     379         [ #  # ]:          0 :                         if (mpihelp_mul_karatsuba_case(ctx->tspace,
     380                 :            :                                                        vp, vsize,
     381                 :            :                                                        up, usize,
     382                 :            :                                                        ctx->next) < 0)
     383                 :            :                                 return -ENOMEM;
     384                 :            :                 }
     385                 :            : 
     386                 :          0 :                 cy = mpihelp_add_n(prodp, prodp, ctx->tspace, vsize);
     387                 :          0 :                 mpihelp_add_1(prodp + vsize, ctx->tspace + vsize, usize, cy);
     388                 :            :         }
     389                 :            : 
     390                 :            :         return 0;
     391                 :            : }
     392                 :            : 
     393                 :         11 : void mpihelp_release_karatsuba_ctx(struct karatsuba_ctx *ctx)
     394                 :            : {
     395                 :         11 :         struct karatsuba_ctx *ctx2;
     396                 :            : 
     397         [ -  + ]:         11 :         if (ctx->tp)
     398                 :          0 :                 mpi_free_limb_space(ctx->tp);
     399         [ +  - ]:         11 :         if (ctx->tspace)
     400                 :         11 :                 mpi_free_limb_space(ctx->tspace);
     401         [ -  + ]:         11 :         for (ctx = ctx->next; ctx; ctx = ctx2) {
     402                 :          0 :                 ctx2 = ctx->next;
     403         [ #  # ]:          0 :                 if (ctx->tp)
     404                 :          0 :                         mpi_free_limb_space(ctx->tp);
     405         [ #  # ]:          0 :                 if (ctx->tspace)
     406                 :          0 :                         mpi_free_limb_space(ctx->tspace);
     407                 :          0 :                 kfree(ctx);
     408                 :            :         }
     409                 :         11 : }
     410                 :            : 
     411                 :            : /* Multiply the natural numbers u (pointed to by UP, with USIZE limbs)
     412                 :            :  * and v (pointed to by VP, with VSIZE limbs), and store the result at
     413                 :            :  * PRODP.  USIZE + VSIZE limbs are always stored, but if the input
     414                 :            :  * operands are normalized.  Return the most significant limb of the
     415                 :            :  * result.
     416                 :            :  *
     417                 :            :  * NOTE: The space pointed to by PRODP is overwritten before finished
     418                 :            :  * with U and V, so overlap is an error.
     419                 :            :  *
     420                 :            :  * Argument constraints:
     421                 :            :  * 1. USIZE >= VSIZE.
     422                 :            :  * 2. PRODP != UP and PRODP != VP, i.e. the destination
     423                 :            :  *    must be distinct from the multiplier and the multiplicand.
     424                 :            :  */
     425                 :            : 
     426                 :            : int
     427                 :          0 : mpihelp_mul(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize,
     428                 :            :             mpi_ptr_t vp, mpi_size_t vsize, mpi_limb_t *_result)
     429                 :            : {
     430                 :          0 :         mpi_ptr_t prod_endp = prodp + usize + vsize - 1;
     431                 :          0 :         mpi_limb_t cy;
     432                 :          0 :         struct karatsuba_ctx ctx;
     433                 :            : 
     434         [ #  # ]:          0 :         if (vsize < KARATSUBA_THRESHOLD) {
     435                 :          0 :                 mpi_size_t i;
     436                 :          0 :                 mpi_limb_t v_limb;
     437                 :            : 
     438         [ #  # ]:          0 :                 if (!vsize) {
     439                 :          0 :                         *_result = 0;
     440                 :          0 :                         return 0;
     441                 :            :                 }
     442                 :            : 
     443                 :            :                 /* Multiply by the first limb in V separately, as the result can be
     444                 :            :                  * stored (not added) to PROD.  We also avoid a loop for zeroing.  */
     445                 :          0 :                 v_limb = vp[0];
     446         [ #  # ]:          0 :                 if (v_limb <= 1) {
     447         [ #  # ]:          0 :                         if (v_limb == 1)
     448         [ #  # ]:          0 :                                 MPN_COPY(prodp, up, usize);
     449                 :            :                         else
     450         [ #  # ]:          0 :                                 MPN_ZERO(prodp, usize);
     451                 :            :                         cy = 0;
     452                 :            :                 } else
     453                 :          0 :                         cy = mpihelp_mul_1(prodp, up, usize, v_limb);
     454                 :            : 
     455                 :          0 :                 prodp[usize] = cy;
     456                 :          0 :                 prodp++;
     457                 :            : 
     458                 :            :                 /* For each iteration in the outer loop, multiply one limb from
     459                 :            :                  * U with one limb from V, and add it to PROD.  */
     460         [ #  # ]:          0 :                 for (i = 1; i < vsize; i++) {
     461                 :          0 :                         v_limb = vp[i];
     462         [ #  # ]:          0 :                         if (v_limb <= 1) {
     463                 :          0 :                                 cy = 0;
     464         [ #  # ]:          0 :                                 if (v_limb == 1)
     465                 :          0 :                                         cy = mpihelp_add_n(prodp, prodp, up,
     466                 :            :                                                            usize);
     467                 :            :                         } else
     468                 :          0 :                                 cy = mpihelp_addmul_1(prodp, up, usize, v_limb);
     469                 :            : 
     470                 :          0 :                         prodp[usize] = cy;
     471                 :          0 :                         prodp++;
     472                 :            :                 }
     473                 :            : 
     474                 :          0 :                 *_result = cy;
     475                 :          0 :                 return 0;
     476                 :            :         }
     477                 :            : 
     478                 :          0 :         memset(&ctx, 0, sizeof ctx);
     479         [ #  # ]:          0 :         if (mpihelp_mul_karatsuba_case(prodp, up, usize, vp, vsize, &ctx) < 0)
     480                 :            :                 return -ENOMEM;
     481                 :          0 :         mpihelp_release_karatsuba_ctx(&ctx);
     482                 :          0 :         *_result = *prod_endp;
     483                 :          0 :         return 0;
     484                 :            : }

Generated by: LCOV version 1.14