bsqrtinv.c revision 1.1.1.2 1 1.1 mrg /* mpn_bsqrtinv, compute r such that r^2 * y = 1 (mod 2^{b+1}).
2 1.1 mrg
3 1.1 mrg Contributed to the GNU project by Martin Boij (as part of perfpow.c).
4 1.1 mrg
5 1.1.1.2 mrg Copyright 2009, 2010, 2012, 2015 Free Software Foundation, Inc.
6 1.1 mrg
7 1.1 mrg This file is part of the GNU MP Library.
8 1.1 mrg
9 1.1 mrg The GNU MP Library is free software; you can redistribute it and/or modify
10 1.1.1.2 mrg it under the terms of either:
11 1.1.1.2 mrg
12 1.1.1.2 mrg * the GNU Lesser General Public License as published by the Free
13 1.1.1.2 mrg Software Foundation; either version 3 of the License, or (at your
14 1.1.1.2 mrg option) any later version.
15 1.1.1.2 mrg
16 1.1.1.2 mrg or
17 1.1.1.2 mrg
18 1.1.1.2 mrg * the GNU General Public License as published by the Free Software
19 1.1.1.2 mrg Foundation; either version 2 of the License, or (at your option) any
20 1.1.1.2 mrg later version.
21 1.1.1.2 mrg
22 1.1.1.2 mrg or both in parallel, as here.
23 1.1 mrg
24 1.1 mrg The GNU MP Library is distributed in the hope that it will be useful, but
25 1.1 mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
26 1.1.1.2 mrg or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 1.1.1.2 mrg for more details.
28 1.1 mrg
29 1.1.1.2 mrg You should have received copies of the GNU General Public License and the
30 1.1.1.2 mrg GNU Lesser General Public License along with the GNU MP Library. If not,
31 1.1.1.2 mrg see https://www.gnu.org/licenses/. */
32 1.1 mrg
33 1.1 mrg #include "gmp.h"
34 1.1 mrg #include "gmp-impl.h"
35 1.1 mrg
36 1.1 mrg /* Compute r such that r^2 * y = 1 (mod 2^{b+1}).
37 1.1 mrg Return non-zero if such an integer r exists.
38 1.1 mrg
39 1.1 mrg Iterates
40 1.1 mrg r' <-- (3r - r^3 y) / 2
41 1.1 mrg using Hensel lifting. Since we divide by two, the Hensel lifting is
42 1.1 mrg somewhat degenerates. Therefore, we lift from 2^b to 2^{b+1}-1.
43 1.1 mrg
44 1.1 mrg FIXME:
45 1.1 mrg (1) Simplify to do precision book-keeping in limbs rather than bits.
46 1.1 mrg
47 1.1 mrg (2) Rewrite iteration as
48 1.1 mrg r' <-- r - r (r^2 y - 1) / 2
49 1.1 mrg and take advantage of zero low part of r^2 y - 1.
50 1.1 mrg
51 1.1 mrg (3) Use wrap-around trick.
52 1.1 mrg
53 1.1 mrg (4) Use a small table to get starting value.
54 1.1 mrg */
55 1.1 mrg int
56 1.1 mrg mpn_bsqrtinv (mp_ptr rp, mp_srcptr yp, mp_bitcnt_t bnb, mp_ptr tp)
57 1.1 mrg {
58 1.1.1.2 mrg mp_ptr tp2;
59 1.1 mrg mp_size_t bn, order[GMP_LIMB_BITS + 1];
60 1.1 mrg int i, d;
61 1.1 mrg
62 1.1 mrg ASSERT (bnb > 0);
63 1.1 mrg
64 1.1 mrg bn = 1 + bnb / GMP_LIMB_BITS;
65 1.1 mrg
66 1.1 mrg tp2 = tp + bn;
67 1.1 mrg
68 1.1 mrg rp[0] = 1;
69 1.1 mrg if (bnb == 1)
70 1.1 mrg {
71 1.1 mrg if ((yp[0] & 3) != 1)
72 1.1 mrg return 0;
73 1.1 mrg }
74 1.1 mrg else
75 1.1 mrg {
76 1.1 mrg if ((yp[0] & 7) != 1)
77 1.1 mrg return 0;
78 1.1 mrg
79 1.1 mrg d = 0;
80 1.1 mrg for (; bnb != 2; bnb = (bnb + 2) >> 1)
81 1.1 mrg order[d++] = bnb;
82 1.1 mrg
83 1.1 mrg for (i = d - 1; i >= 0; i--)
84 1.1 mrg {
85 1.1 mrg bnb = order[i];
86 1.1 mrg bn = 1 + bnb / GMP_LIMB_BITS;
87 1.1 mrg
88 1.1.1.2 mrg mpn_sqrlo (tp, rp, bn);
89 1.1.1.2 mrg mpn_mullo_n (tp2, rp, tp, bn); /* tp2 <- rp ^ 3 */
90 1.1.1.2 mrg
91 1.1.1.2 mrg mpn_mul_1 (tp, rp, bn, 3);
92 1.1 mrg
93 1.1 mrg mpn_mullo_n (rp, yp, tp2, bn);
94 1.1 mrg
95 1.1 mrg #if HAVE_NATIVE_mpn_rsh1sub_n
96 1.1 mrg mpn_rsh1sub_n (rp, tp, rp, bn);
97 1.1 mrg #else
98 1.1 mrg mpn_sub_n (tp2, tp, rp, bn);
99 1.1 mrg mpn_rshift (rp, tp2, bn, 1);
100 1.1 mrg #endif
101 1.1 mrg }
102 1.1 mrg }
103 1.1 mrg return 1;
104 1.1 mrg }
105