1 /*
2     Copyright (C) 2008 Peter Shrimpton
3     Copyright (C) 2009 William Hart
4 
5     This file is part of FLINT.
6 
7     FLINT is free software: you can redistribute it and/or modify it under
8     the terms of the GNU Lesser General Public License (LGPL) as published
9     by the Free Software Foundation; either version 2.1 of the License, or
10     (at your option) any later version.  See <https://www.gnu.org/licenses/>.
11 */
12 
13 #include <gmp.h>
14 #include "flint.h"
15 #include "ulong_extras.h"
16 
17 n_pair_t
lchain_precomp(mp_limb_t m,mp_limb_t a,mp_limb_t n,double npre)18 lchain_precomp(mp_limb_t m, mp_limb_t a, mp_limb_t n, double npre)
19 {
20     n_pair_t current = {0, 0}, old;
21     int length, i;
22     mp_limb_t power, xy, xx, yy;
23 
24     old.x = UWORD(2);
25     old.y = a;
26 
27     length = FLINT_BIT_COUNT(m);
28     power = (UWORD(1) << (length - 1));
29 
30     for (i = 0; i < length; i++)
31     {
32         xy = n_submod(n_mulmod_precomp(old.x, old.y, n, npre), a, n);
33 
34         if (m & power)
35         {
36             yy = n_submod(n_mulmod_precomp(old.y, old.y, n, npre), UWORD(2), n);
37             current.x = xy;
38             current.y = yy;
39         }
40         else
41         {
42             xx = n_submod(n_mulmod_precomp(old.x, old.x, n, npre), UWORD(2), n);
43             current.x = xx;
44             current.y = xy;
45         }
46 
47         power >>= 1;
48         old = current;
49     }
50 
51     return current;
52 }
53 
54 n_pair_t
lchain2_preinv(mp_limb_t m,mp_limb_t a,mp_limb_t n,mp_limb_t ninv)55 lchain2_preinv(mp_limb_t m, mp_limb_t a, mp_limb_t n, mp_limb_t ninv)
56 {
57     n_pair_t current = {0, 0}, old;
58     int length, i;
59     mp_limb_t power, xy, xx, yy;
60 
61     old.x = UWORD(2);
62     old.y = a;
63 
64     length = FLINT_BIT_COUNT(m);
65     power = (UWORD(1) << (length - 1));
66 
67     for (i = 0; i < length; i++)
68     {
69         xy = n_submod(n_mulmod2_preinv(old.x, old.y, n, ninv), a, n);
70 
71         if (m & power)
72         {
73             yy = n_submod(n_mulmod2_preinv(old.y, old.y, n, ninv), UWORD(2), n);
74             current.x = xy;
75             current.y = yy;
76         }
77         else
78         {
79             xx = n_submod(n_mulmod2_preinv(old.x, old.x, n, ninv), UWORD(2), n);
80             current.x = xx;
81             current.y = xy;
82         }
83 
84         power >>= 1;
85         old = current;
86     }
87 
88     return current;
89 }
90 
91 int
n_is_probabprime_lucas(mp_limb_t n)92 n_is_probabprime_lucas(mp_limb_t n)
93 {
94     int i, D, Q;
95     mp_limb_t A;
96     mp_limb_t left, right;
97     n_pair_t V;
98 
99     D = 0;
100     Q = 0;
101 
102     if (((n % 2) == 0) || (FLINT_ABS((mp_limb_signed_t) n) <= 2))
103     {
104         return (n == UWORD(2));
105     }
106 
107     for (i = 0; i < 100; i++)
108     {
109         D = 5 + 2 * i;
110         if (n_gcd(D, n % D) != UWORD(1))
111         {
112             if (n == D)
113                 continue;
114             else
115                 return 0;
116         }
117         if (i % 2 == 1)
118             D = -D;
119         if (n_jacobi(D, n) == -1)
120             break;
121     }
122 
123     if (i == 100)
124     {
125         return (n_is_square(n) ? -1 : 1);
126     }
127 
128     Q = (1 - D) / 4;
129     if (Q < 0)
130     {
131         if (n < UWORD(52))
132         {
133             while (Q < 0)
134                 Q += n;
135             A = n_submod(n_invmod(Q, n), UWORD(2), n);
136         }
137         else
138             A = n_submod(n_invmod(Q + n, n), UWORD(2), n);
139     }
140     else
141     {
142         if (n < UWORD(52))
143         {
144             while (Q >= n)
145                 Q -= n;
146             A = n_submod(n_invmod(Q, n), UWORD(2), n);
147         }
148         else
149             A = n_submod(n_invmod(Q, n), UWORD(2), n);
150     }
151 
152     if (FLINT_BIT_COUNT(n) <= FLINT_D_BITS)
153     {
154         double npre = n_precompute_inverse(n);
155         V = lchain_precomp(n + 1, A, n, npre);
156 
157         left = n_mulmod_precomp(A, V.x, n, npre);
158         right = n_mulmod_precomp(2, V.y, n, npre);
159     }
160     else
161     {
162         mp_limb_t ninv = n_preinvert_limb(n);
163         V = lchain2_preinv(n + 1, A, n, ninv);
164 
165         left = n_mulmod_precomp(A, V.x, n, ninv);
166         right = n_mulmod_precomp(2, V.y, n, ninv);
167     }
168 
169     return (left == right);
170 }
171