Line data Source code
1 : /* Copyright (C) 2013 The PARI group.
2 :
3 : This file is part of the PARI/GP package.
4 :
5 : PARI/GP is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 2 of the License, or (at your option) any later
8 : version. It is distributed in the hope that it will be useful, but WITHOUT
9 : ANY WARRANTY WHATSOEVER.
10 :
11 : Check the License for details. You should have received a copy of it, along
12 : with the package; see the file 'COPYING'. If not, write to the Free Software
13 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
14 :
15 : #include "pari.h"
16 : #include "paripriv.h"
17 :
18 : #define DEBUGLEVEL DEBUGLEVEL_fflog
19 :
20 : /* Let [ be the following order on Fp: 0 [ p-1 [ 1 [ p-2 [ 2 .. [ p\2
21 : and [[ the lexicographic extension of [ to Fp[T]. Compute the
22 : isomorphism (Fp[X], [[) -> (N,<) on P */
23 :
24 : static long
25 392039 : Flx_cindex(GEN P, ulong p)
26 : {
27 392039 : long d = degpol(P), i;
28 392039 : ulong s = 0, p2 = (p-1)>>1;
29 1781887 : for (i = 0; i <= d; ++i)
30 : {
31 1389848 : ulong x = P[d-i+2];
32 1389848 : if (x<=p2) x = 2*x; else x = 1+2*(p-1-x);
33 1389848 : s = p*s+x;
34 : }
35 392039 : return s;
36 : }
37 :
38 : /* Compute the polynomial immediately after t for the [[ order */
39 :
40 : static void
41 433353 : Flx_cnext(GEN t, ulong p)
42 : {
43 : long i;
44 433353 : long p2 = p>>1;
45 433353 : for(i=2;;i++)
46 554545 : if (t[i]==p2)
47 121192 : t[i]=0;
48 : else
49 : {
50 433353 : t[i] = t[i]<p2 ? p-1-t[i]: p-t[i];
51 433353 : break;
52 : }
53 433353 : }
54 :
55 : static int
56 28 : has_deg1_auto(GEN T, ulong p)
57 : {
58 28 : long i, n = degpol(T);
59 28 : GEN a = polx_Flx(get_Flx_var(T));
60 672 : for (i=1; i<n; i++)
61 : {
62 644 : a = Flxq_powu(a, p, T, p);
63 644 : if (degpol(a)==1) return 1;
64 : }
65 28 : return 0;
66 : }
67 :
68 : static void
69 1057 : smallirred_Flx_next(GEN a, long p)
70 : {
71 : do
72 : {
73 : long i;
74 1057 : for(i=2;;i++)
75 1449 : if (++a[i]==p) a[i]=0;
76 1057 : else break;
77 1057 : } while (!Flx_is_irred(a, p) || has_deg1_auto(a,p) );
78 28 : }
79 :
80 : /* Avoid automorphisms of degree 1 */
81 : static GEN
82 28 : smallirred_Flx(long p, ulong n, long sv)
83 : {
84 28 : GEN a = zero_zv(n+2);
85 28 : a[1] = sv; a[3] = 1; a[n+2] = 1;
86 28 : smallirred_Flx_next(a, p);
87 28 : return a;
88 : }
89 :
90 : struct Flxq_log_rel
91 : {
92 : long nbrel;
93 : GEN rel;
94 : long nb;
95 : long r, off, nbmax, nbexp;
96 : ulong nbtest;
97 : };
98 :
99 : static GEN
100 4643 : cindex_Flx(long c, long d, ulong p, long v)
101 : {
102 4643 : GEN P = cgetg(d+3, t_VECSMALL);
103 : long i;
104 4643 : P[1] = v;
105 31664 : for (i = 0; i <= d; ++i)
106 : {
107 27021 : ulong x = c%p;
108 27021 : P[i+2] = (x&1) ? p-1-(x>>1) : x>>1;
109 27021 : c/=p;
110 : }
111 4643 : return Flx_renormalize(P, d+3);
112 : }
113 :
114 : static GEN
115 11156 : factorel(GEN h, ulong p)
116 : {
117 11156 : GEN F = Flx_factor(h, p);
118 11157 : GEN F1 = gel(F, 1), F2 = gel(F, 2);
119 11157 : long i, l1 = lg(F1)-1;
120 11157 : GEN p2 = cgetg(l1+1, t_VECSMALL);
121 11157 : GEN e2 = cgetg(l1+1, t_VECSMALL);
122 52838 : for (i = 1; i <= l1; ++i)
123 : {
124 41681 : p2[i] = Flx_cindex(gel(F1, i), p);
125 41680 : e2[i] = F2[i];
126 : }
127 11157 : return mkmat2(p2, e2);
128 : }
129 :
130 : static long
131 74256 : Flx_addifsmooth3(pari_sp *av, struct Flxq_log_rel *r, GEN h, long u, long v, long w, ulong p)
132 : {
133 74256 : long off = r->off;
134 74256 : r->nbtest++;
135 74256 : if (Flx_is_smooth(h, r->r, p))
136 : {
137 5670 : GEN z = factorel(h, p);
138 5670 : if (v<0)
139 1225 : z = mkmat2(vecsmall_append(gel(z,1),off+u),vecsmall_append(gel(z,2),-1));
140 : else
141 13335 : z = famatsmall_reduce(mkmat2(
142 4445 : vecsmall_concat(gel(z,1),mkvecsmall3(off+u,off+v,off+w)),
143 4445 : vecsmall_concat(gel(z,2),mkvecsmall3(-1,-1,-1))));
144 5670 : gel(r->rel,++r->nbrel) = gerepilecopy(*av,z);
145 5670 : if (DEBUGLEVEL && (r->nbrel&511UL)==0)
146 0 : err_printf("%ld%% ",r->nbrel*100/r->nbexp);
147 5670 : *av = avma;
148 68586 : } else set_avma(*av);
149 74256 : return r->nbrel==r->nb || r->nbrel==r->nbmax;
150 : }
151 :
152 : static void
153 433419 : Flx_renormalize_inplace(GEN x, long lx)
154 : {
155 : long i;
156 4932704 : for (i = lx-1; i>1; i--)
157 4930023 : if (x[i]) break;
158 433419 : setlg(x, i+1);
159 433525 : }
160 :
161 : /*
162 : Let T*X^e=C^3-R
163 : a+b+c = 0
164 : (C+a)*(C+b)*(C+c) = C^3+ (a*b+a*c+b*c)*C+a*b*c
165 : = R + (a*b+a*c+b*c)*C+a*b*c
166 : = R + (a*b-c^2)*C+a*b*c
167 : */
168 : static void
169 14 : Flxq_log_cubic(struct Flxq_log_rel *r, GEN C, GEN R, ulong p)
170 : {
171 14 : long l = lg(C);
172 14 : GEN a = zero_zv(l); /*We allocate one extra word to catch overflow*/
173 14 : GEN b = zero_zv(l);
174 14 : pari_sp av = avma;
175 : long i,j,k;
176 2800 : for(i=0; ; i++, Flx_cnext(a, p))
177 : {
178 2800 : Flx_renormalize_inplace(a, l+1);
179 2800 : r->nb++;
180 2800 : if (Flx_addifsmooth3(&av, r, Flx_add(a, C, p), i, -1, -1, p)) return;
181 29400 : for(j=2; j<=l; j++) b[j] = 0;
182 353129 : for(j=0; j<=i; j++, Flx_cnext(b, p))
183 : {
184 : GEN h,c;
185 : GEN pab,pabc,pabc2;
186 350343 : Flx_renormalize_inplace(b, l+1);
187 350343 : c = Flx_neg(Flx_add(a,b,p),p);
188 350343 : k = Flx_cindex(c, p);
189 350343 : if (k > j) continue;
190 71456 : pab = Flx_mul(a, b, p);
191 71456 : pabc = Flx_mul(pab,c,p);
192 71456 : pabc2= Flx_sub(pab,Flx_sqr(c,p),p);
193 71456 : h = Flx_add(R,Flx_add(Flx_mul(C,pabc2,p),pabc,p), p);
194 71456 : h = Flx_normalize(h, p);
195 71456 : if (Flx_addifsmooth3(&av, r, h, i, j, k, p)) return;
196 : }
197 : }
198 : }
199 :
200 : static GEN
201 73 : Flxq_log_find_rel(GEN b, long r, GEN T, ulong p, GEN *g, long *e)
202 : {
203 73 : pari_sp av = avma;
204 : while (1)
205 3835 : {
206 : GEN M;
207 3908 : *g = Flxq_mul(*g, b, T, p); (*e)++;
208 3908 : M = Flx_halfgcd(*g,T,p);
209 3908 : if (Flx_is_smooth(gcoeff(M,1,1), r, p))
210 : {
211 487 : GEN z = Flx_add(Flx_mul(gcoeff(M,1,1),*g,p), Flx_mul(gcoeff(M,1,2),T,p),p);
212 487 : if (Flx_is_smooth(z, r, p))
213 : {
214 73 : GEN F = factorel(z, p);
215 73 : GEN G = factorel(gcoeff(M,1,1), p);
216 73 : GEN rel = mkmat2(vecsmall_concat(gel(F, 1),gel(G, 1)),
217 73 : vecsmall_concat(gel(F, 2),zv_neg(gel(G, 2))));
218 73 : return gc_all(av,2,&rel,g);
219 : }
220 : }
221 3835 : if (gc_needed(av,2))
222 : {
223 0 : if (DEBUGMEM>1) pari_warn(warnmem,"Flxq_log_find_rel");
224 0 : *g = gerepilecopy(av, *g);
225 : }
226 : }
227 : }
228 :
229 : /* Generalised Odlyzko formulae ( EUROCRYPT '84, LNCS 209, pp. 224-314, 1985. ) */
230 : /* Return the number of monic, k smooth, degree n polynomials for k=1..r */
231 : static GEN
232 2233 : smoothness_vec(ulong p, long r, long n)
233 : {
234 : long i,j,k;
235 2233 : GEN R = cgetg(r+1, t_VEC), pp = utoipos(p);
236 2233 : GEN V = cgetg(n+1, t_VEC);
237 20496 : for (j = 1; j <= n; ++j)
238 18263 : gel(V, j) = binomialuu(p+j-1,j);
239 2233 : gel(R, 1) = gel(V, n);
240 5341 : for (k = 2; k <= r; ++k)
241 : {
242 3108 : GEN W = cgetg(n+1, t_VEC);
243 3108 : GEN Ik = ffnbirred(pp, k);
244 36029 : for (j = 1; j <= n; ++j)
245 : {
246 32921 : long l = j/k;
247 32921 : GEN s = gen_0;
248 32921 : pari_sp av2 = avma;
249 32921 : if (l*k == j)
250 : {
251 10801 : s = binomial(addiu(Ik,l-1), l);
252 10801 : l--;
253 : }
254 119847 : for (i = 0; i <= l; ++i)
255 86926 : s = addii(s, mulii(gel(V, j-k*i), binomial(addis(Ik,i-1), i)));
256 32921 : gel(W, j) = gerepileuptoint(av2, s);
257 : }
258 3108 : V = W;
259 3108 : gel(R, k) = gel(V, n);
260 : }
261 2233 : return R;
262 : }
263 :
264 : /* Solve N^2*pr/6 + N*prC = N+fb
265 : N^2*pr/6 + N*(prC-1) -fb = 0
266 : */
267 :
268 : static GEN
269 1729 : smooth_cost(GEN fb, GEN pr, GEN prC)
270 : {
271 1729 : GEN a = gdivgu(pr,6);
272 1729 : GEN b = gsubgs(prC,1);
273 1729 : GEN c = gneg(fb);
274 1729 : GEN vD = gsqrt(gsub(gsqr(b),gmul2n(gmul(a,c),2)),BIGDEFAULTPREC);
275 1729 : return ceil_safe(gdiv(gsub(vD,b),gmul2n(a,1)));
276 : }
277 :
278 : /* Return best choice of r.
279 : We loop over d until there is sufficiently many triples (a,b,c) (a+b+c=0)
280 : of degree <=d with respect to the probability of smoothness of (a*b-c^2)*C
281 : */
282 :
283 : static GEN
284 315 : smooth_best(long p, long n, long *pt_r, long *pt_nb)
285 : {
286 315 : pari_sp av = avma, av2;
287 315 : GEN bestc = NULL, pp = utoipos(p);
288 315 : long bestr = 0, bestFB = 0;
289 315 : long r,d, dC = (n+2)/3;
290 819 : for (r = 1; r < dC; ++r)
291 : {
292 504 : GEN fb = ffsumnbirred(pp, r);
293 504 : GEN smoothC = smoothness_vec(p,r,dC);
294 504 : GEN prC = gdiv(gel(smoothC,r), powuu(p,dC));
295 504 : ulong rels = 0;
296 504 : av2 = avma;
297 2023 : for(d=0; d<dC && rels < ULONG_MAX; d++)
298 : {
299 : GEN c;
300 1729 : long dt = dC+2*d;
301 1729 : GEN smooth = smoothness_vec(p,r,dt);
302 1729 : GEN pr = gdiv(gel(smooth,r), powuu(p,dt));
303 1729 : GEN FB = addii(fb,powuu(p,d));
304 1729 : GEN N = smooth_cost(subiu(FB,rels),pr,prC);
305 1729 : GEN Nmax = powuu(p,d+1);
306 1729 : if (gcmp(N,Nmax) >= 0)
307 : {
308 1519 : rels = itou_or_0(addui(rels, gceil(gmul(gdivgu(sqri(Nmax),6),pr))));
309 1519 : if (!rels) rels = ULONG_MAX;
310 1519 : set_avma(av2);
311 1519 : continue;
312 : }
313 210 : c = gdivgu(addii(powuu(p,2*d),sqri(N)),6);
314 210 : FB = addii(FB,N);
315 210 : if ((!bestc || gcmp(gmul2n(c,r), gmul2n(bestc,bestr)) < 0))
316 : {
317 133 : if (DEBUGLEVEL)
318 0 : err_printf("r=%ld d=%ld fb=%Ps early rels=%lu P=%.5Pe -> C=%.5Pe \n",
319 : r, dt, FB, rels, pr, c);
320 133 : bestc = c;
321 133 : bestr = r;
322 133 : bestFB = itos_or_0(FB);
323 : }
324 210 : break;
325 : }
326 : }
327 315 : *pt_r=bestr;
328 315 : *pt_nb=bestFB;
329 315 : return bestc ? gerepileupto(av, gceil(bestc)): NULL;
330 : }
331 :
332 : static GEN
333 28 : check_kernel(long r, GEN M, long nbi, long nbrow, GEN T, ulong p, GEN m)
334 : {
335 28 : pari_sp av = avma;
336 28 : long N = 3*upowuu(p, r);
337 28 : GEN K = FpMs_leftkernel_elt(M, nbrow, m);
338 28 : long i, f=0, tbs;
339 28 : long lm = lgefint(m), u=1;
340 : GEN tab, g;
341 28 : GEN q = powuu(p,degpol(T));
342 28 : GEN idx = diviiexact(subiu(q,1),m);
343 : pari_timer ti;
344 28 : if (DEBUGLEVEL) timer_start(&ti);
345 224 : while (signe(gel(K,u))==0)
346 196 : u++;
347 28 : K = FpC_Fp_mul(K, Fp_inv(gel(K, u), m), m);
348 28 : g = Flxq_pow(cindex_Flx(u, r, p, T[1]), idx, T, p);
349 28 : tbs = maxss(1, expu(nbi/expi(m)));
350 28 : tab = Flxq_pow_init(g, q, tbs, T, p);
351 28 : setlg(K, N);
352 46662 : for (i=1; i<N; i++)
353 : {
354 46634 : GEN k = gel(K,i);
355 46634 : pari_sp av = avma;
356 51031 : long t = signe(k) && Flx_equal(Flxq_pow_table(tab, k, T, p),
357 4397 : Flxq_pow(cindex_Flx(i,r,p,T[1]), idx, T, p));
358 46634 : set_avma(av);
359 46634 : if (!t)
360 42237 : gel(K,i) = cgetineg(lm);
361 : else
362 4397 : f++;
363 : }
364 28 : if (DEBUGLEVEL) timer_printf(&ti,"found %ld/%ld logs", f, nbi);
365 28 : if (f < maxss(3,maxss(p/2,nbi/p))) return NULL; /* Not enough logs found */
366 28 : return gerepilecopy(av, K);
367 : }
368 :
369 : static GEN
370 28 : Flxq_log_rec(GEN W, GEN a, long r, GEN T, ulong p, GEN m)
371 : {
372 28 : long AV = 0, u = 1;
373 28 : GEN g = a, b;
374 : pari_timer ti;
375 280 : while (!equali1(gel(W,u)))
376 252 : u++;
377 28 : b = cindex_Flx(u, r, p, T[1]);
378 : while(1)
379 17 : {
380 : long i, l;
381 : GEN V, F, E, Ao;
382 45 : timer_start(&ti);
383 45 : V = Flxq_log_find_rel(b, r, T, p, &g, &AV);
384 45 : if (DEBUGLEVEL>1) timer_printf(&ti,"%ld-smooth element",r);
385 45 : F = gel(V,1); E = gel(V,2);
386 45 : l = lg(F);
387 45 : Ao = gen_0;
388 339 : for(i=1; i<l; i++)
389 : {
390 311 : GEN R = gel(W,F[i]);
391 311 : if (signe(R)<=0)
392 17 : break;
393 294 : Ao = Fp_add(Ao, mulis(R, E[i]), m);
394 : }
395 45 : if (i==l) return subis(Ao,AV);
396 : }
397 : }
398 :
399 : static int
400 301 : Flxq_log_use_index_cubic(GEN m, GEN T0, ulong p)
401 : {
402 301 : pari_sp av = avma;
403 301 : long n = get_Flx_degree(T0), r, nb;
404 301 : GEN cost = smooth_best(p, n, &r, &nb);
405 301 : GEN cost_rho = sqrti(shifti(m,2));
406 301 : int use = (cost && gcmp(cost,cost_rho)<0);
407 301 : set_avma(av);
408 301 : return use;
409 : }
410 :
411 : static GEN
412 14 : Flxq_log_index_cubic(GEN a0, GEN b0, GEN m, GEN T0, ulong p)
413 : {
414 14 : long n = get_Flx_degree(T0), r, nb;
415 14 : pari_sp av = avma;
416 : struct Flxq_log_rel rel;
417 : long nbi;
418 : GEN W, M, S, T, a, b, Ao, Bo, e, C, R;
419 : pari_timer ti;
420 14 : GEN cost = smooth_best(p, n, &r, &nb);
421 14 : GEN cost_rho = sqrti(shifti(m,2));
422 14 : if (!cost || gcmp(cost,cost_rho)>=0) return gc_NULL(av);
423 14 : nbi = itos(ffsumnbirred(stoi(p), r));
424 14 : if (DEBUGLEVEL)
425 : {
426 0 : err_printf("Size FB=%ld, looking for %ld relations, %Ps tests needed\n", nbi, nb,cost);
427 0 : timer_start(&ti);
428 : }
429 14 : T = smallirred_Flx(p,n,get_Flx_var(T0));
430 : for(;;)
431 : {
432 14 : S = Flx_ffisom(T0,T,p);
433 14 : a = Flx_Flxq_eval(a0, S, T, p);
434 14 : b = Flx_Flxq_eval(b0, S, T, p);
435 14 : C = Flx_shift(pol1_Flx(get_Flx_var(T)), (n+2)/3);
436 14 : R = Flxq_powu(C,3,T,p);
437 14 : if (DEBUGLEVEL)
438 0 : timer_printf(&ti," model change: %Ps",Flx_to_ZX(T));
439 14 : rel.nbmax=2*nb;
440 14 : M = cgetg(rel.nbmax+1, t_VEC);
441 14 : rel.rel = M;
442 14 : rel.nbrel = 0; rel.r = r; rel.off = 3*upowuu(p,r);
443 14 : rel.nb = nbi; rel.nbexp = nb; rel.nbtest=0;
444 14 : Flxq_log_cubic(&rel, C, R, p);
445 14 : setlg(M,1+rel.nbrel);
446 14 : if (DEBUGLEVEL)
447 : {
448 0 : err_printf("\n");
449 0 : timer_printf(&ti," %ld relations, %ld generators (%ld tests)",rel.nbrel,rel.nb,rel.nbtest);
450 : }
451 14 : W = check_kernel(r, M, nbi, rel.off + rel.nb - nbi, T, p, m);
452 14 : if (W) break;
453 0 : if (DEBUGLEVEL) timer_start(&ti);
454 0 : smallirred_Flx_next(T,p);
455 : }
456 14 : if (DEBUGLEVEL) timer_start(&ti);
457 14 : Ao = Flxq_log_rec(W, a, r, T, p, m);
458 14 : if (DEBUGLEVEL) timer_printf(&ti,"smooth element");
459 14 : Bo = Flxq_log_rec(W, b, r, T, p, m);
460 14 : if (DEBUGLEVEL) timer_printf(&ti,"smooth generator");
461 14 : e = Fp_div(Ao, Bo, m);
462 14 : if (!Flx_equal(Flxq_pow(b0, e, T0, p), a0)) pari_err_BUG("Flxq_log");
463 14 : return gerepileupto(av, e);
464 : }
465 :
466 22820 : INLINE GEN Flx_frob(GEN u, ulong p) { return Flx_inflate(u, p); }
467 :
468 : static GEN
469 39470 : rel_Coppersmith(long r, GEN u, GEN v, long h, GEN R, long d, ulong p)
470 : {
471 : GEN a, b, F, G, M;
472 39470 : if (degpol(Flx_gcd(u,v,p))) return NULL;
473 39390 : a = Flx_add(Flx_shift(u, h), v, p);
474 39432 : if (lgpol(a)==0 || !Flx_is_smooth(a, r, p)) return NULL;
475 9649 : b = Flx_add(Flx_mul(R, Flx_frob(u, p), p), Flx_shift(Flx_frob(v, p),d), p);
476 9698 : if (!Flx_is_smooth(b, r, p)) return NULL;
477 2607 : F = factorel(a, p); G = factorel(b, p);
478 5214 : M = mkmat2(vecsmall_concat(gel(F, 1), vecsmall_append(gel(G, 1), 2*p)),
479 5214 : vecsmall_concat(zv_z_mul(gel(F, 2),p), vecsmall_append(zv_neg(gel(G, 2)),d)));
480 2607 : return famatsmall_reduce(M);
481 : }
482 :
483 : GEN
484 1444 : Flxq_log_Coppersmith_worker(GEN u, long i, GEN V, GEN R)
485 : {
486 1444 : long r = V[1], h = V[2], d = V[3], p = V[4], dT = V[5];
487 1444 : pari_sp ltop = avma;
488 1444 : GEN v = zero_zv(dT+2);
489 1449 : GEN L = cgetg(2*i+1, t_VEC);
490 1446 : pari_sp av = avma;
491 : long j;
492 1446 : long nbtest=0, rel = 1;
493 1446 : ulong lu = Flx_lead(u), lv;
494 80177 : for (j=1; j<=i; j++)
495 : {
496 : GEN z;
497 78723 : Flx_cnext(v, p);
498 78743 : Flx_renormalize_inplace(v, dT+2);
499 78862 : lv = Flx_lead(v);
500 78850 : set_avma(av);
501 78846 : if (lu != 1 && lv != 1) continue;
502 48344 : if (degpol(Flx_gcd(u, v, p))!=0) continue;
503 32549 : if (lu==1)
504 : {
505 20098 : z = rel_Coppersmith(r, u, v, h, R, d, p);
506 20151 : nbtest++;
507 20151 : if (z) { gel(L, rel++) = z; av = avma; }
508 : }
509 32602 : if (i==j) continue;
510 32418 : if (lv==1)
511 : {
512 19367 : z = rel_Coppersmith(r, v, u, h, R, d, p);
513 19386 : nbtest++;
514 19386 : if (z) { gel(L, rel++) = z; av = avma; }
515 : }
516 : }
517 1454 : setlg(L,rel);
518 1454 : return gerepilecopy(ltop, mkvec2(stoi(nbtest), L));
519 : }
520 :
521 : static GEN
522 14 : Flxq_log_Coppersmith(long nbrel, long r, GEN T, ulong p)
523 : {
524 : pari_sp av;
525 14 : long dT = degpol(T);
526 14 : long h = dT/p, d = dT-(h*p);
527 14 : GEN R = Flx_sub(Flx_shift(pol1_Flx(T[1]), dT), T, p);
528 14 : GEN u = zero_zv(dT+2);
529 : GEN done;
530 14 : long nbtest = 0, rel = 0;
531 14 : GEN M = cgetg(nbrel+1, t_VEC);
532 14 : long i = 1;
533 14 : GEN worker = snm_closure(is_entry("_Flxq_log_Coppersmith_worker"),
534 : mkvec2(mkvecsmall5(r,h,d,p,dT), R));
535 : struct pari_mt pt;
536 14 : long running, pending = 0, stop=0;
537 14 : if (DEBUGLEVEL) err_printf("Coppersmith (R = %ld): ",degpol(R));
538 14 : mt_queue_start(&pt, worker);
539 14 : av = avma;
540 1530 : while ((running = !stop) || pending)
541 : {
542 : GEN L;
543 : long l, j;
544 1516 : Flx_cnext(u, p);
545 1516 : Flx_renormalize_inplace(u, dT+2);
546 1516 : mt_queue_submit(&pt, 0, running ? mkvec2(u, stoi(i)): NULL);
547 1516 : done = mt_queue_get(&pt, NULL, &pending);
548 1516 : if (!done) continue;
549 1454 : L = gel(done, 2); nbtest += itos(gel(done,1));
550 1454 : l = lg(L);
551 1454 : if (l > 1)
552 : {
553 3427 : for (j=1; j<l; j++)
554 : {
555 2487 : if (rel>nbrel) break;
556 2429 : gel(M,++rel) = gel(L,j);
557 2429 : if (DEBUGLEVEL && (rel&511UL)==0)
558 0 : err_printf("%ld%%[%ld] ",rel*100/nbrel,i);
559 : }
560 998 : av = avma;
561 : }
562 456 : else set_avma(av);
563 1454 : if (rel>nbrel) stop = 1;
564 1454 : i++;
565 : }
566 14 : mt_queue_end(&pt);
567 14 : if (DEBUGLEVEL) err_printf(": %ld tests\n", nbtest);
568 14 : return M;
569 : }
570 :
571 : static GEN Flxq_log_Coppersmith_d(GEN W, GEN g, long r, GEN T, ulong p, GEN mo);
572 :
573 : static GEN
574 64 : Flxq_log_from_rel(GEN W, GEN rel, long r, GEN T, ulong p, GEN m)
575 : {
576 64 : pari_sp av = avma;
577 64 : GEN F = gel(rel,1), E = gel(rel,2), o = gen_0;
578 64 : long i, l = lg(F);
579 478 : for(i=1; i<l; i++)
580 : {
581 414 : GEN R = gel(W, F[i]);
582 414 : if (signe(R)==0) /* Already failed */
583 0 : return NULL;
584 414 : else if (signe(R)<0) /* Not yet tested */
585 : {
586 15 : setsigne(gel(W,F[i]),0);
587 15 : R = Flxq_log_Coppersmith_d(W, cindex_Flx(F[i],r,p,T[1]), r, T, p, m);
588 15 : if (!R) return NULL;
589 : }
590 414 : o = Fp_add(o, mulis(R, E[i]), m);
591 : }
592 64 : return gerepileuptoint(av, o);
593 : }
594 :
595 : static GEN
596 64 : Flxq_log_Coppersmith_d(GEN W, GEN g, long r, GEN T, ulong p, GEN mo)
597 : {
598 64 : pari_sp av = avma, av2;
599 64 : long dg = degpol(g), k = r-1, m = maxss((dg-k)/2,0);
600 64 : long i, j, l = dg-m, N;
601 64 : GEN v = cgetg(k+m+1,t_MAT);
602 64 : long dT = degpol(T);
603 64 : long h = dT/p, d = dT-h*p;
604 64 : GEN R = Flx_rem(Flx_shift(pol1_Flx(T[1]), dT), T, p);
605 64 : GEN z = Flx_rem(Flx_shift(pol1_Flx(T[1]), h), g, p);
606 424 : for(i=1; i<=k+m; i++)
607 : {
608 360 : gel(v,i) = Flx_to_Flv(Flx_shift(z,-l),m);
609 360 : z = Flx_rem(Flx_shift(z,1),g,p);
610 : }
611 64 : v = Flm_ker(v,p);
612 369 : for(i=1; i<=k; i++)
613 305 : gel(v,i) = Flv_to_Flx(gel(v,i),T[1]);
614 64 : N = upowuu(p,k);
615 64 : av2 = avma;
616 1721 : for (i=1; i<N; i++)
617 : {
618 : GEN p0,q,qh,a,b;
619 1721 : ulong el = i;
620 1721 : set_avma(av2);
621 1721 : q = pol0_Flx(T[1]);
622 10058 : for (j=1; j<=k; j++)
623 : {
624 8337 : ulong r = el % p;
625 8337 : el /= p;
626 8337 : if (r) q = Flx_add(q, Flx_Fl_mul(gel(v,j), r, p), p);
627 : }
628 1721 : qh = Flx_shift(q, h);
629 1721 : p0 = Flx_rem(qh, g, p);
630 1721 : b = Flx_sub(Flx_mul(R, Flx_frob(q, p), p), Flx_shift(Flx_frob(p0, p), d), p);
631 1721 : if (lgpol(b)==0 || !Flx_is_smooth(b, r, p)) continue;
632 160 : a = Flx_div(Flx_sub(qh, p0, p), g, p);
633 160 : if (degpol(Flx_gcd(a, q, p)) && degpol(Flx_gcd(a, p0 ,p)))
634 48 : continue;
635 112 : if (!(lgpol(a)==0 || !Flx_is_smooth(a, r, p)))
636 : {
637 64 : GEN F = factorel(b, p);
638 64 : GEN G = factorel(a, p);
639 64 : GEN FG = vecsmall_concat(vecsmall_append(gel(F, 1), 2*p), gel(G, 1));
640 64 : GEN E = vecsmall_concat(vecsmall_append(gel(F, 2), -d),
641 64 : zv_z_mul(gel(G, 2),-p));
642 64 : GEN R = famatsmall_reduce(mkmat2(FG, E));
643 64 : GEN l = Flxq_log_from_rel(W, R, r, T, p, mo);
644 64 : if (!l) continue;
645 64 : l = Fp_divu(l,p,mo);
646 64 : if (dg <= r)
647 : {
648 15 : long idx = Flx_cindex(g, p);
649 15 : affii(l, gel(W, idx));
650 15 : if (DEBUGLEVEL>1) err_printf("Found %lu\n", idx);
651 : }
652 64 : return gerepileuptoint(av, l);
653 : }
654 : }
655 0 : set_avma(av);
656 0 : return NULL;
657 : }
658 :
659 : static GEN
660 28 : Flxq_log_Coppersmith_rec(GEN W, long r2, GEN a, long r, GEN T, ulong p, GEN m)
661 : {
662 28 : GEN b = polx_Flx(T[1]);
663 28 : long AV = 0;
664 28 : GEN g = a, bad = pol0_Flx(T[1]);
665 : pari_timer ti;
666 : while(1)
667 0 : {
668 : long i, l;
669 : GEN V, F, E, Ao;
670 28 : timer_start(&ti);
671 28 : V = Flxq_log_find_rel(b, r2, T, p, &g, &AV);
672 28 : if (DEBUGLEVEL>1) timer_printf(&ti,"%ld-smooth element",r2);
673 28 : F = gel(V,1); E = gel(V,2);
674 28 : l = lg(F);
675 28 : Ao = gen_0;
676 203 : for(i=1; i<l; i++)
677 : {
678 175 : GEN Fi = cindex_Flx(F[i], r2, p, T[1]);
679 : GEN R;
680 175 : if (degpol(Fi) <= r)
681 : {
682 126 : if (signe(gel(W,F[i]))==0)
683 0 : break;
684 126 : else if (signe(gel(W,F[i]))<0)
685 : {
686 0 : setsigne(gel(W,F[i]),0);
687 0 : R = Flxq_log_Coppersmith_d(W,Fi,r,T,p,m);
688 : } else
689 126 : R = gel(W,F[i]);
690 : }
691 : else
692 : {
693 49 : if (Flx_equal(Fi,bad)) break;
694 49 : R = Flxq_log_Coppersmith_d(W,Fi,r,T,p,m);
695 49 : if (!R) bad = Fi;
696 : }
697 175 : if (!R) break;
698 175 : Ao = Fp_add(Ao, mulis(R, E[i]), m);
699 : }
700 28 : if (i==l) return subis(Ao,AV);
701 : }
702 : }
703 :
704 : static GEN
705 14 : Flxq_log_index_Coppersmith(GEN a0, GEN b0, GEN m, GEN T0, ulong p)
706 : {
707 14 : pari_sp av = avma;
708 14 : GEN M, S, a, b, Ao=NULL, Bo=NULL, W, e;
709 : pari_timer ti;
710 14 : double rf = p ==3 ? 1.2 : .9;
711 14 : long n = degpol(T0), r = (long) sqrt(n*rf);
712 : GEN T;
713 14 : long r2 = 3*r/2;
714 14 : long nbi = itos(ffsumnbirred(utoipos(p), r)), nbrel=nbi*5/4;
715 14 : if (DEBUGLEVEL)
716 : {
717 0 : err_printf("Coppersmith: Parameters r=%ld r2=%ld\n", r,r2);
718 0 : err_printf("Coppersmith: Size FB=%ld rel. needed=%ld\n", nbi, nbrel);
719 0 : timer_start(&ti);
720 : }
721 14 : T = smallirred_Flx(p,n,get_Flx_var(T0));
722 14 : S = Flx_ffisom(T0,T,p);
723 14 : a = Flx_Flxq_eval(a0, S, T, p);
724 14 : b = Flx_Flxq_eval(b0, S, T, p);
725 14 : if (DEBUGLEVEL) timer_printf(&ti,"model change");
726 14 : M = Flxq_log_Coppersmith(nbrel, r, T, p);
727 14 : if (DEBUGLEVEL) timer_printf(&ti,"relations");
728 14 : W = check_kernel(r, M, nbi, 3*upowuu(p,r), T, p, m);
729 14 : timer_start(&ti);
730 14 : Ao = Flxq_log_Coppersmith_rec(W, r2, a, r, T, p, m);
731 14 : if (DEBUGLEVEL) timer_printf(&ti,"smooth element");
732 14 : Bo = Flxq_log_Coppersmith_rec(W, r2, b, r, T, p, m);
733 14 : if (DEBUGLEVEL) timer_printf(&ti,"smooth generator");
734 14 : e = Fp_div(Ao, Bo, m);
735 14 : if (!Flx_equal(Flxq_pow(b0,e,T0,p),a0)) pari_err_BUG("Flxq_log");
736 14 : return gerepileupto(av, e);
737 : }
738 :
739 : GEN
740 28 : Flxq_log_index(GEN a, GEN b, GEN m, GEN T, ulong p)
741 : {
742 28 : long d = get_Flx_degree(T);
743 28 : if (p==3 || (p==5 && d>41))
744 14 : return Flxq_log_index_Coppersmith(a, b, m, T, p);
745 14 : else return Flxq_log_index_cubic(a, b, m, T, p);
746 : }
747 :
748 : int
749 157985 : Flxq_log_use_index(GEN m, GEN T, ulong p)
750 : {
751 157985 : long d = get_Flx_degree(T);
752 157985 : if (p==3 || (p==5 && d>41))
753 24226 : return 1;
754 133759 : else if (d<=4 || d==6)
755 133458 : return 0;
756 : else
757 301 : return Flxq_log_use_index_cubic(m, T, p);
758 : }
|