]> www.ginac.de Git - cln.git/blob - src/numtheory/cl_nt_sqrtmodp.cc
Make @exec_prefix@ usable in shell scripts.
[cln.git] / src / numtheory / cl_nt_sqrtmodp.cc
1 // sqrt_mod_p().
2
3 // General includes.
4 #include "cl_sysdep.h"
5
6 // Specification.
7 #include "cl_numtheory.h"
8
9
10 // Implementation.
11
12 #include "cl_I.h"
13 #include "cl_abort.h"
14
15 #undef floor
16 #include <math.h>
17 #define floor cln_floor
18
19 // Algorithm 1 (for very small p only):
20 // Try different values.
21 // Assume p is prime and a nonzero square in Z/pZ.
22 static uint32 search_sqrt (uint32 p, uint32 a)
23 {
24         var uint32 x = 1;
25         var uint32 x2 = 1;
26         loop {
27                 // 0 < x <= p/2, x2 = x^2 mod p.
28                 if (x2 == a)
29                         return x;
30                 x2 += x; x++; x2 += x;
31                 if (x2 >= p)
32                         x2 -= p;
33         }
34 }
35
36 // Algorithm 2 (for p > 2 only):
37 // Cantor-Zassenhaus.
38 // [Beth et al.: Computer Algebra, 1988, Kapitel 5.3.3.]
39 // [Cohen, A Course in Computational Algebraic Number Theory,
40 //  Section 3.4.4., Algorithm 3.4.6.]
41 // Input: R = Z/pZ with p>2, and a (nonzero square in R).
42 static const sqrt_mod_p_t cantor_zassenhaus_sqrt (const cl_modint_ring& R, const cl_MI& a);
43         // Compute in the polynomial ring R[X]/(X^2-a).
44         struct pol2 {
45                 // A polynomial c0+c1*X mod (X^2-a)
46                 cl_MI c0;
47                 cl_MI c1;
48                 // Constructor.
49                 pol2 (const cl_MI& _c0, const cl_MI& _c1) : c0 (_c0), c1 (_c1) {}
50         };
51         struct pol2ring {
52                 const cl_modint_ring& R;
53                 const cl_MI& a;
54                 const pol2 zero ()
55                 {
56                         return pol2(R->zero(),R->zero());
57                 }
58                 const pol2 one ()
59                 {
60                         return pol2(R->one(),R->zero());
61                 }
62                 const pol2 plus (const pol2& u, const pol2& v)
63                 {
64                         return pol2(u.c0+v.c0, u.c1+v.c1);
65                 }
66                 const pol2 minus (const pol2& u, const pol2& v)
67                 {
68                         return pol2(u.c0-v.c0, u.c1-v.c1);
69                 }
70                 const pol2 mul (const pol2& u, const pol2& v)
71                 {
72                         return pol2(u.c0*v.c0+u.c1*v.c1*a, u.c0*v.c1+u.c1*v.c0);
73                 }
74                 const pol2 square (const pol2& u)
75                 {
76                         return pol2(::square(u.c0) + ::square(u.c1)*a, (u.c0*u.c1)<<1);
77                 }
78                 const pol2 expt_pos (const pol2& x, const cl_I& y)
79                 {
80                         // Right-Left Binary, [Cohen, Algorithm 1.2.1.]
81                         var pol2 a = x;
82                         var cl_I b = y;
83                         while (!oddp(b)) { a = square(a); b = b = b >> 1; } // a^b = x^y
84                         var pol2 c = a;
85                         until (eq(b,1)) {
86                                 b = b >> 1;
87                                 a = square(a);
88                                 // a^b*c = x^y
89                                 if (oddp(b))
90                                         c = mul(a,c);
91                         }
92                         return c;
93                 }
94                 const pol2 random ()
95                 {
96                         return pol2(R->random(),R->random());
97                 }
98                 // Computes the degree of gcd(u(X),X^2-a) and, if it is 1,
99                 // also the zero if this polynomial of degree 1.
100                 struct gcd_result {
101                         cl_composite_condition* condition;
102                         int gcd_degree;
103                         cl_MI solution;
104                         // Constructors.
105                         gcd_result (cl_composite_condition* c) : condition (c) {}
106                         gcd_result (int deg) : condition (NULL), gcd_degree (deg) {}
107                         gcd_result (int deg, const cl_MI& sol) : condition (NULL), gcd_degree (deg), solution (sol) {}
108                 };
109                 const gcd_result gcd (const pol2& u)
110                 {
111                         if (zerop(u.c1))
112                                 // constant polynomial u(X)
113                                 if (zerop(u.c0))
114                                         return gcd_result(2);
115                                 else
116                                         return gcd_result(0);
117                         // u(X) = c0 + c1*X has zero -c0/c1.
118                         var cl_MI_x c1inv = R->recip(u.c1);
119                         if (c1inv.condition)
120                                 return c1inv.condition;
121                         var cl_MI z = -u.c0*c1inv;
122                         if (::square(z) == a)
123                                 return gcd_result(1,z);
124                         else
125                                 return gcd_result(0);
126                 }
127                 // Constructor.
128                 pol2ring (const cl_modint_ring& _R, const cl_MI& _a) : R (_R), a (_a) {}
129         };
130 static const sqrt_mod_p_t cantor_zassenhaus_sqrt (const cl_modint_ring& R, const cl_MI& a)
131 {
132         var pol2ring PR = pol2ring(R,a);
133         var cl_I& p = R->modulus;
134         // Assuming p is a prime, then R[X]/(X^2-a) is the direct product of
135         // two rings R[X]/(X-sqrt(a)), each being isomorphic to R. Thus taking
136         // a (p-1)/2-th power in this ring will return one of (0,+1,-1) in
137         // each ring, with independent probabilities (1/p, (p-1)/2p, (p-1)/2p).
138         // For any polynomial u(X), setting v(X) := u(X)^((p-1)/2) yields
139         // gcd(u(X),X^2-a) * gcd(v(X)-1,X^2-a) * gcd(v(X)+1,X^2-a) = X^2-a.
140         // If p is not prime, all of these gcd's are likely to be 1.
141         var cl_I e = (p-1) >> 1;
142         loop {
143                 // Choose a random polynomial u(X) in the ring.
144                 var pol2 u = PR.random();
145                 // Compute v(X) = u(X)^((p-1)/2).
146                 var pol2 v = PR.expt_pos(u,e);
147                 // Compute the three gcds.
148                 var pol2ring::gcd_result g1 = PR.gcd(PR.minus(v,PR.one()));
149                 if (g1.condition)
150                         return g1.condition;
151                 if (g1.gcd_degree == 1)
152                         return sqrt_mod_p_t(2,g1.solution,-g1.solution);
153                 if (g1.gcd_degree == 2)
154                         continue;
155                 var pol2ring::gcd_result g2 = PR.gcd(PR.plus(v,PR.one()));
156                 if (g2.condition)
157                         return g2.condition;
158                 if (g2.gcd_degree == 1)
159                         return sqrt_mod_p_t(2,g2.solution,-g2.solution);
160                 if (g2.gcd_degree == 2)
161                         continue;
162                 var pol2ring::gcd_result g3 = PR.gcd(u);
163                 if (g3.condition)
164                         return g3.condition;
165                 if (g3.gcd_degree == 1)
166                         return sqrt_mod_p_t(2,g3.solution,-g3.solution);
167                 if (g1.gcd_degree + g2.gcd_degree + g3.gcd_degree < 2)
168                         // If the sum of the degrees of the gcd is != 2,
169                         // p cannot be prime.
170                         return new cl_composite_condition(p);
171         }
172 }
173
174 // Algorithm 3 (for p > 2 only):
175 // Tonelli-Shanks.
176 // [Cohen, A Course in Computational Algebraic Number Theory,
177 //  Section 1.5.1., Algorithm 1.5.1.]
178 static const sqrt_mod_p_t tonelli_shanks_sqrt (const cl_modint_ring& R, const cl_MI& a)
179 {
180         // Idea:
181         // Write p-1 = 2^e*m, m odd. G = (Z/pZ)^* (cyclic of order p-1) has
182         // subgroups G_0 < G_1 < ... < G_e, G_j of order 2^j. (G_e is called
183         // the "2-Sylow subgroup" of G.) More precisely
184         //          G_j = { x in (Z/pZ)^* : x^(2^j) = 1 },
185         //        G/G_j = { x^(2^j) : x in (Z/pZ)^* }.
186         // We compute the square root of a first in G/G_e, then lift it to
187         // G/G_(e-1), etc., up to G/G_0.
188         // Start with b = a^((m+1)/2), then (a^-1*b^2)^(2^e) = 1, i.e.
189         // a = b^2 in G/G_e.
190         // Lifting from G/G_j to G/G_(j-1) is easy: Assume a = b^2 in G/G_j.
191         // If a = b^2 in G/G_(j-1), then nothing needs to be done. Else
192         // a^-1*b^2 is in G_j \ G_(j-1). If j=e, a^-1*b^2 is a non-square
193         // mod p, hence a is a non-square as well, contradiction. If j<e,
194         // take h in G_(j+1) \ G_j, so that h^2 in G_j \ G_(j-1), and
195         // a^-1*b^2*h^2 is in G_(j-1). So multiply b with h.
196         var cl_I& p = R->modulus;
197         var uintL e = ord2(p-1);
198         var cl_I m = (p-1) >> e;
199         // p-1 = 2^e*m, m odd.
200         // We will have the invariant c = a^-1*b^2 in G/G_j.
201         var uintL j = e;
202         // Initialize b = a^((m+1)/2), c = a^m, but avoid to divide by a.
203         var cl_MI c = R->expt_pos(a,(m-1)>>1);
204         var cl_MI b = R->mul(a,c);
205         c = R->mul(b,c);
206         // Find h in G_e \ G_(e-1): h = h'^m, where h' is any non-square.
207         var cl_MI h;
208         if (e==1)
209                 h = - R->one();
210         else {
211                 // Since this computation is a bit costly, we cache its result
212                 // on the ring's property list.
213                 static const cl_symbol key = (cl_symbol)(cl_string)"generator of 2-Sylow subgroup of (Z/pZ)^*";
214                 struct cl_sylow2gen_property : public cl_property {
215                         SUBCLASS_cl_property();
216                 public:
217                         cl_I h_rep;
218                         // Constructor.
219                         cl_sylow2gen_property (const cl_symbol& k, const cl_MI& h) : cl_property (k), h_rep (h.rep) {}
220                 };
221                 var cl_sylow2gen_property* prop = (cl_sylow2gen_property*) R->get_property(key);
222                 if (prop)
223                         h = cl_MI(R,prop->h_rep);
224                 else {
225                         do { h = R->random(); }
226                            until (jacobi(R->retract(h),p) == -1);
227                         h = R->expt_pos(h,m);
228                         R->add_property(new cl_sylow2gen_property(key,h));
229                 }
230         }
231         do {
232                 // Now c = a^-1*b^2 in G_j, h in G_j \ G_(j-1).
233                 // Determine the smallest i such that c in G_i.
234                 var uintL i = 0;
235                 var cl_MI ci = c; // c_i = c^(2^i)
236                 for ( ; i < j; i++, ci = R->square(ci))
237                         if (ci == R->one())
238                                 break;
239                 if (i==j)
240                         // Some problem: if j=e, a non-square, if j<e, the
241                         // previous iteration didn't do its job correctly.
242                         // Indicates that p is not prime.
243                         return new cl_composite_condition(p);
244                 // OK, i < j.
245                 for (var uintL count = j-i-1; count > 0; count--)
246                         h = R->square(h);
247                 // Now h in G_(i+1) \ G_i.
248                 b = R->mul(b,h);
249                 h = R->square(h);
250                 c = R->mul(c,h);
251                 // Now c = a^-1*b^2 in G_(i-1), h in G_i \ G_(i-1).
252                 j = i;
253         } while (j > 0);
254         if (R->square(b) != a)
255                 // Problem again.
256                 return new cl_composite_condition(p);
257         return sqrt_mod_p_t(2,b,-b);
258 }
259
260 // Break-Even-Points (on a i486 with 33 MHz):
261 // Algorithm 1 fastest for p < 1500..2000
262 // Algorithm 3 generally fastest for p > 2000.
263 // But the running time of algorithm 3 is proportional to e^2.
264 // For large e, algorithm 2 becomes faster.
265 // l=50 bits: for e >= 40
266 // l=100 bits: for e >= 55
267 // l=200 bits: for e >= 80
268 // l=400 bits: for e >= 130
269 // in general something like  e > l/(log(l)/(2*log(2))-1).
270
271 const sqrt_mod_p_t sqrt_mod_p (const cl_modint_ring& R, const cl_MI& a)
272 {
273         if (!(a.ring() == R)) cl_abort();
274         var cl_I& p = R->modulus;
275         var cl_I aa = R->retract(a);
276         switch (jacobi(aa,p)) {
277                 case -1: // no solution
278                         return sqrt_mod_p_t(0);
279                 case 0: // gcd(aa,p) > 1
280                         if (zerop(a))
281                                 // one solution
282                                 return sqrt_mod_p_t(1,a);
283                         else
284                                 // found factor of p
285                                 return new cl_composite_condition(p,gcd(aa,p));
286                 case 1: // two solutions
287                         break;
288         }
289         if (p < 2000) {
290                 // Algorithm 1.
291                 var cl_I x1 = search_sqrt(cl_I_to_UL(p),cl_I_to_UL(aa));
292                 var cl_I x2 = p-x1;
293                 if (x1==x2) // can only happen when p = 2
294                         return sqrt_mod_p_t(1,R->canonhom(x1));
295                 else
296                         return sqrt_mod_p_t(2,R->canonhom(x1),R->canonhom(x2));
297         }
298         var uintL l = integer_length(p);
299         var uintL e = ord2(p-1);
300         //if (e > 30 && e > l/(log((double)l)*0.72-1))
301         if (e > 30 && e > l/(log((double)l)*0.92-2.41))
302                 // Algorithm 2.
303                 return cantor_zassenhaus_sqrt(R,a);
304         else
305                 // Algorithm 3.
306                 return tonelli_shanks_sqrt(R,a);
307 }