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

     1  /* mpn_brootinv, compute r such that r^k * y = 1 (mod 2^b).
     2  
     3     Contributed to the GNU project by Martin Boij (as part of perfpow.c).
     4  
     5  Copyright 2009, 2010, 2012, 2013 Free Software Foundation, Inc.
     6  
     7  This file is part of the GNU MP Library.
     8  
     9  The GNU MP Library is free software; you can redistribute it and/or modify
    10  it under the terms of either:
    11  
    12    * the GNU Lesser General Public License as published by the Free
    13      Software Foundation; either version 3 of the License, or (at your
    14      option) any later version.
    15  
    16  or
    17  
    18    * the GNU General Public License as published by the Free Software
    19      Foundation; either version 2 of the License, or (at your option) any
    20      later version.
    21  
    22  or both in parallel, as here.
    23  
    24  The GNU MP Library is distributed in the hope that it will be useful, but
    25  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    26  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    27  for more details.
    28  
    29  You should have received copies of the GNU General Public License and the
    30  GNU Lesser General Public License along with the GNU MP Library.  If not,
    31  see https://www.gnu.org/licenses/.  */
    32  
    33  #include "gmp.h"
    34  #include "gmp-impl.h"
    35  
    36  /* Computes a^e (mod B). Uses right-to-left binary algorithm, since
    37     typical use will have e small. */
    38  static mp_limb_t
    39  powlimb (mp_limb_t a, mp_limb_t e)
    40  {
    41    mp_limb_t r;
    42  
    43    for (r = 1; e > 0; e >>= 1, a *= a)
    44      if (e & 1)
    45        r *= a;
    46  
    47    return r;
    48  }
    49  
    50  /* Compute r such that r^k * y = 1 (mod B^n).
    51  
    52     Iterates
    53       r' <-- k^{-1} ((k+1) r - r^{k+1} y) (mod 2^b)
    54     using Hensel lifting, each time doubling the number of known bits in r.
    55  
    56     Works just for odd k.  Else the Hensel lifting degenerates.
    57  
    58     FIXME:
    59  
    60       (1) Make it work for k == GMP_LIMB_MAX (k+1 below overflows).
    61  
    62       (2) Rewrite iteration as
    63  	   r' <-- r - k^{-1} r (r^k y - 1)
    64  	 and take advantage of the zero low part of r^k y - 1.
    65  
    66       (3) Use wrap-around trick.
    67  
    68       (4) Use a small table to get starting value.
    69  
    70     Scratch need: 5*bn, where bn = ceil (bnb / GMP_NUMB_BITS).
    71  */
    72  
    73  void
    74  mpn_brootinv (mp_ptr rp, mp_srcptr yp, mp_size_t bn, mp_limb_t k, mp_ptr tp)
    75  {
    76    mp_ptr tp2, tp3;
    77    mp_limb_t kinv, k2, r0, y0;
    78    mp_size_t order[GMP_LIMB_BITS + 1];
    79    int i, d;
    80  
    81    ASSERT (bn > 0);
    82    ASSERT ((k & 1) != 0);
    83  
    84    tp2 = tp + bn;
    85    tp3 = tp + 2 * bn;
    86    k2 = k + 1;
    87  
    88    binvert_limb (kinv, k);
    89  
    90    /* 4-bit initial approximation:
    91  
    92     y%16 | 1  3  5  7  9 11 13 15,
    93      k%4 +-------------------------+k2%4
    94       1  | 1 11 13  7  9  3  5 15  |  2
    95       3  | 1  3  5  7  9 11 13 15  |  0
    96  
    97    */
    98    y0 = yp[0];
    99  
   100    r0 = y0 ^ (((y0 << 1) ^ (y0 << 2)) & (k2 << 2) & 8);		/* 4 bits */
   101    r0 = kinv * (k2 * r0 - y0 * powlimb(r0, k2 & 0x7f));		/* 8 bits */
   102    r0 = kinv * (k2 * r0 - y0 * powlimb(r0, k2 & 0x7fff));	/* 16 bits */
   103  #if GMP_NUMB_BITS > 16
   104    {
   105      unsigned prec = 16;
   106      do
   107        {
   108  	r0 = kinv * (k2 * r0 - y0 * powlimb(r0, k2));
   109  	prec *= 2;
   110        }
   111      while (prec < GMP_NUMB_BITS);
   112    }
   113  #endif
   114  
   115    rp[0] = r0;
   116    if (bn == 1)
   117      return;
   118  
   119    /* This initialization doesn't matter for the result (any garbage is
   120       cancelled in the iteration), but proper initialization makes
   121       valgrind happier. */
   122    MPN_ZERO (rp+1, bn-1);
   123  
   124    d = 0;
   125    for (; bn > 1; bn = (bn + 1) >> 1)
   126      order[d++] = bn;
   127  
   128    for (i = d - 1; i >= 0; i--)
   129      {
   130        bn = order[i];
   131  
   132        mpn_mul_1 (tp, rp, bn, k2);
   133  
   134        mpn_powlo (tp2, rp, &k2, 1, bn, tp3);
   135        mpn_mullo_n (rp, yp, tp2, bn);
   136  
   137        mpn_sub_n (tp2, tp, rp, bn);
   138        mpn_pi1_bdiv_q_1 (rp, tp2, bn, k, kinv, 0);
   139      }
   140  }