github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/mpn/generic/sec_pi1_div.c (about)

     1  /* mpn_sec_pi1_div_qr, mpn_sec_pi1_div_r -- Compute Q = floor(U / V), U = U
     2     mod V.  Side-channel silent under the assumption that the used instructions
     3     are side-channel silent.
     4  
     5     Contributed to the GNU project by Torbjörn Granlund.
     6  
     7     THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
     8     SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
     9     GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
    10  
    11  Copyright 2011-2013 Free Software Foundation, Inc.
    12  
    13  This file is part of the GNU MP Library.
    14  
    15  The GNU MP Library is free software; you can redistribute it and/or modify
    16  it under the terms of either:
    17  
    18    * the GNU Lesser General Public License as published by the Free
    19      Software Foundation; either version 3 of the License, or (at your
    20      option) any later version.
    21  
    22  or
    23  
    24    * the GNU General Public License as published by the Free Software
    25      Foundation; either version 2 of the License, or (at your option) any
    26      later version.
    27  
    28  or both in parallel, as here.
    29  
    30  The GNU MP Library is distributed in the hope that it will be useful, but
    31  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    32  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    33  for more details.
    34  
    35  You should have received copies of the GNU General Public License and the
    36  GNU Lesser General Public License along with the GNU MP Library.  If not,
    37  see https://www.gnu.org/licenses/.  */
    38  
    39  #include "gmp.h"
    40  #include "gmp-impl.h"
    41  #include "longlong.h"
    42  
    43  /* This side-channel silent division algorithm reduces the partial remainder by
    44     GMP_NUMB_BITS/2 bits at a time, compared to GMP_NUMB_BITS for the main
    45     division algorithm.  We actually do not insist on reducing by exactly
    46     GMP_NUMB_BITS/2, but may leave a partial remainder that is D*B^i to 3D*B^i
    47     too large (B is the limb base, D is the divisor, and i is the induction
    48     variable); the subsequent step will handle the extra partial remainder bits.
    49  
    50     With that partial remainder reduction, each step generates a quotient "half
    51     limb".  The outer loop generates two quotient half limbs, an upper (q1h) and
    52     a lower (q0h) which are stored sparsely in separate limb arrays.  These
    53     arrays are added at the end; using separate arrays avoids data-dependent
    54     carry propagation which could else pose a side-channel leakage problem.
    55  
    56     The quotient half limbs may be between -3 to 0 from the accurate value
    57     ("accurate" being the one which corresponds to a reduction to a principal
    58     partial remainder).  Too small quotient half limbs correspond to too large
    59     remainders, which we reduce later, as described above.
    60  
    61     In order to keep quotients from getting too big, corresponding to a negative
    62     partial remainder, we use an inverse which is slightly smaller than usually.
    63  */
    64  
    65  #if OPERATION_sec_pi1_div_qr
    66  /* Needs (dn + 1) + (nn - dn) + (nn - dn) = 2nn - dn + 1 limbs at tp. */
    67  #define FNAME mpn_sec_pi1_div_qr
    68  #define Q(q) q,
    69  #define RETTYPE mp_limb_t
    70  #endif
    71  #if OPERATION_sec_pi1_div_r
    72  /* Needs (dn + 1) limbs at tp.  */
    73  #define FNAME mpn_sec_pi1_div_r
    74  #define Q(q)
    75  #define RETTYPE void
    76  #endif
    77  
    78  RETTYPE
    79  FNAME (Q(mp_ptr qp)
    80         mp_ptr np, mp_size_t nn,
    81         mp_srcptr dp, mp_size_t dn,
    82         mp_limb_t dinv,
    83         mp_ptr tp)
    84  {
    85    mp_limb_t nh, cy, q1h, q0h, dummy, cnd;
    86    mp_size_t i;
    87    mp_ptr hp;
    88  #if OPERATION_sec_pi1_div_qr
    89    mp_limb_t qh;
    90    mp_ptr qlp, qhp;
    91  #endif
    92  
    93    ASSERT (dn >= 1);
    94    ASSERT (nn >= dn);
    95    ASSERT ((dp[dn - 1] & GMP_NUMB_HIGHBIT) != 0);
    96  
    97    if (nn == dn)
    98      {
    99        cy = mpn_sub_n (np, np, dp, dn);
   100        mpn_cnd_add_n (cy, np, np, dp, dn);
   101  #if OPERATION_sec_pi1_div_qr
   102        return 1 - cy;
   103  #else
   104        return;
   105  #endif
   106      }
   107  
   108    /* Create a divisor copy shifted half a limb.  */
   109    hp = tp;					/* (dn + 1) limbs */
   110    hp[dn] = mpn_lshift (hp, dp, dn, GMP_NUMB_BITS / 2);
   111  
   112  #if OPERATION_sec_pi1_div_qr
   113    qlp = tp + (dn + 1);				/* (nn - dn) limbs */
   114    qhp = tp + (nn + 1);				/* (nn - dn) limbs */
   115  #endif
   116  
   117    np += nn - dn;
   118    nh = 0;
   119  
   120    for (i = nn - dn - 1; i >= 0; i--)
   121      {
   122        np--;
   123  
   124        nh = (nh << GMP_NUMB_BITS/2) + (np[dn] >> GMP_NUMB_BITS/2);
   125        umul_ppmm (q1h, dummy, nh, dinv);
   126        q1h += nh;
   127  #if OPERATION_sec_pi1_div_qr
   128        qhp[i] = q1h;
   129  #endif
   130        mpn_submul_1 (np, hp, dn + 1, q1h);
   131  
   132        nh = np[dn];
   133        umul_ppmm (q0h, dummy, nh, dinv);
   134        q0h += nh;
   135  #if OPERATION_sec_pi1_div_qr
   136        qlp[i] = q0h;
   137  #endif
   138        nh -= mpn_submul_1 (np, dp, dn, q0h);
   139      }
   140  
   141    /* 1st adjustment depends on extra high remainder limb.  */
   142    cnd = nh != 0;				/* FIXME: cmp-to-int */
   143  #if OPERATION_sec_pi1_div_qr
   144    qlp[0] += cnd;
   145  #endif
   146    nh -= mpn_cnd_sub_n (cnd, np, np, dp, dn);
   147  
   148    /* 2nd adjustment depends on remainder/divisor comparison as well as whether
   149       extra remainder limb was nullified by previous subtract.  */
   150    cy = mpn_sub_n (np, np, dp, dn);
   151    cy = cy - nh;
   152  #if OPERATION_sec_pi1_div_qr
   153    qlp[0] += 1 - cy;
   154  #endif
   155    mpn_cnd_add_n (cy, np, np, dp, dn);
   156  
   157    /* 3rd adjustment depends on remainder/divisor comparison.  */
   158    cy = mpn_sub_n (np, np, dp, dn);
   159  #if OPERATION_sec_pi1_div_qr
   160    qlp[0] += 1 - cy;
   161  #endif
   162    mpn_cnd_add_n (cy, np, np, dp, dn);
   163  
   164  #if OPERATION_sec_pi1_div_qr
   165    /* Combine quotient halves into final quotient.  */
   166    qh = mpn_lshift (qhp, qhp, nn - dn, GMP_NUMB_BITS/2);
   167    qh += mpn_add_n (qp, qhp, qlp, nn - dn);
   168  
   169    return qh;
   170  #else
   171    return;
   172  #endif
   173  }