Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

Testing latest pari + WASM + node.js... and it works?! Wow.

28486 views
License: GPL3
ubuntu2004
1
/* Copyright (C) 2012 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_ellcard
19
20
/* Not so fast arithmetic with points over elliptic curves over Fq,
21
small characteristic. */
22
23
/***********************************************************************/
24
/** **/
25
/** FlxqE **/
26
/** **/
27
/***********************************************************************/
28
29
/* Theses functions deal with point over elliptic curves over Fq defined
30
* by an equation of the form y^2=x^3+a4*x+a6.
31
* Most of the time a6 is omitted since it can be recovered from any point
32
* on the curve.
33
*/
34
35
GEN
36
RgE_to_FlxqE(GEN x, GEN T, ulong p)
37
{
38
if (ell_is_inf(x)) return x;
39
retmkvec2(Rg_to_Flxq(gel(x,1),T,p),Rg_to_Flxq(gel(x,2),T,p));
40
}
41
42
GEN
43
FlxqE_changepoint(GEN x, GEN ch, GEN T, ulong p)
44
{
45
pari_sp av = avma;
46
GEN p1,z,u,r,s,t,v,v2,v3;
47
if (ell_is_inf(x)) return x;
48
u = gel(ch,1); r = gel(ch,2);
49
s = gel(ch,3); t = gel(ch,4);
50
v = Flxq_inv(u, T, p); v2 = Flxq_sqr(v, T, p); v3 = Flxq_mul(v,v2, T, p);
51
p1 = Flx_sub(gel(x,1),r, p);
52
z = cgetg(3,t_VEC);
53
gel(z,1) = Flxq_mul(v2, p1, T, p);
54
gel(z,2) = Flxq_mul(v3, Flx_sub(gel(x,2), Flx_add(Flxq_mul(s, p1, T, p),t, p), p), T, p);
55
return gerepileupto(av, z);
56
}
57
58
GEN
59
FlxqE_changepointinv(GEN x, GEN ch, GEN T, ulong p)
60
{
61
GEN u, r, s, t, X, Y, u2, u3, u2X, z;
62
if (ell_is_inf(x)) return x;
63
X = gel(x,1); Y = gel(x,2);
64
u = gel(ch,1); r = gel(ch,2);
65
s = gel(ch,3); t = gel(ch,4);
66
u2 = Flxq_sqr(u, T, p); u3 = Flxq_mul(u,u2, T, p);
67
u2X = Flxq_mul(u2,X, T, p);
68
z = cgetg(3, t_VEC);
69
gel(z,1) = Flx_add(u2X,r, p);
70
gel(z,2) = Flx_add(Flxq_mul(u3,Y, T, p), Flx_add(Flxq_mul(s,u2X, T, p), t, p), p);
71
return z;
72
}
73
74
static GEN
75
nonsquare_Flxq(GEN T, ulong p)
76
{
77
pari_sp av = avma;
78
long n = degpol(T), vs = T[1];
79
GEN a;
80
if (odd(n))
81
return mkvecsmall2(vs, nonsquare_Fl(p));
82
do
83
{
84
set_avma(av);
85
a = random_Flx(n, vs, p);
86
} while (Flxq_issquare(a, T, p));
87
return a;
88
}
89
90
void
91
Flxq_elltwist(GEN a, GEN a6, GEN T, ulong p, GEN *pt_a, GEN *pt_a6)
92
{
93
GEN d = nonsquare_Flxq(T, p);
94
GEN d2 = Flxq_sqr(d, T, p), d3 = Flxq_mul(d2, d, T, p);
95
if (typ(a)==t_VECSMALL)
96
{
97
*pt_a = Flxq_mul(a, d2, T, p);
98
*pt_a6 = Flxq_mul(a6, d3, T, p);
99
} else
100
{
101
*pt_a = mkvec(Flxq_mul(gel(a,1), d, T, p));
102
*pt_a6 = Flxq_mul(a6, d3, T, p);
103
}
104
}
105
106
static GEN
107
FlxqE_dbl_slope(GEN P, GEN a4, GEN T, ulong p, GEN *slope)
108
{
109
GEN x, y, Q;
110
if (ell_is_inf(P) || !lgpol(gel(P,2))) return ellinf();
111
x = gel(P,1); y = gel(P,2);
112
if (p==3UL)
113
*slope = typ(a4)==t_VEC ? Flxq_div(Flxq_mul(x, gel(a4, 1), T, p), y, T, p)
114
: Flxq_div(a4, Flx_neg(y, p), T, p);
115
else
116
{
117
GEN sx = Flx_add(Flx_triple(Flxq_sqr(x, T, p), p), a4, p);
118
*slope = Flxq_div(sx, Flx_double(y, p), T, p);
119
}
120
Q = cgetg(3,t_VEC);
121
gel(Q, 1) = Flx_sub(Flxq_sqr(*slope, T, p), Flx_double(x, p), p);
122
if (typ(a4)==t_VEC) gel(Q, 1) = Flx_sub(gel(Q, 1), gel(a4, 1), p);
123
gel(Q, 2) = Flx_sub(Flxq_mul(*slope, Flx_sub(x, gel(Q, 1), p), T, p), y, p);
124
return Q;
125
}
126
127
GEN
128
FlxqE_dbl(GEN P, GEN a4, GEN T, ulong p)
129
{
130
pari_sp av = avma;
131
GEN slope;
132
return gerepileupto(av, FlxqE_dbl_slope(P,a4, T, p,&slope));
133
}
134
135
static GEN
136
FlxqE_add_slope(GEN P, GEN Q, GEN a4, GEN T, ulong p, GEN *slope)
137
{
138
GEN Px, Py, Qx, Qy, R;
139
if (ell_is_inf(P)) return Q;
140
if (ell_is_inf(Q)) return P;
141
Px = gel(P,1); Py = gel(P,2);
142
Qx = gel(Q,1); Qy = gel(Q,2);
143
if (Flx_equal(Px, Qx))
144
{
145
if (Flx_equal(Py, Qy))
146
return FlxqE_dbl_slope(P, a4, T, p, slope);
147
else
148
return ellinf();
149
}
150
*slope = Flxq_div(Flx_sub(Py, Qy, p), Flx_sub(Px, Qx, p), T, p);
151
R = cgetg(3,t_VEC);
152
gel(R, 1) = Flx_sub(Flx_sub(Flxq_sqr(*slope, T, p), Px, p), Qx, p);
153
if (typ(a4)==t_VEC) gel(R, 1) = Flx_sub(gel(R, 1),gel(a4, 1), p);
154
gel(R, 2) = Flx_sub(Flxq_mul(*slope, Flx_sub(Px, gel(R, 1), p), T, p), Py, p);
155
return R;
156
}
157
158
GEN
159
FlxqE_add(GEN P, GEN Q, GEN a4, GEN T, ulong p)
160
{
161
pari_sp av = avma;
162
GEN slope;
163
return gerepileupto(av, FlxqE_add_slope(P,Q,a4, T, p,&slope));
164
}
165
166
static GEN
167
FlxqE_neg_i(GEN P, ulong p)
168
{
169
if (ell_is_inf(P)) return P;
170
return mkvec2(gel(P,1), Flx_neg(gel(P,2), p));
171
}
172
173
GEN
174
FlxqE_neg(GEN P, GEN T, ulong p)
175
{
176
(void) T;
177
if (ell_is_inf(P)) return ellinf();
178
return mkvec2(gcopy(gel(P,1)), Flx_neg(gel(P,2), p));
179
}
180
181
GEN
182
FlxqE_sub(GEN P, GEN Q, GEN a4, GEN T, ulong p)
183
{
184
pari_sp av = avma;
185
GEN slope;
186
return gerepileupto(av, FlxqE_add_slope(P, FlxqE_neg_i(Q, p), a4, T, p, &slope));
187
}
188
189
struct _FlxqE
190
{
191
GEN a4, a6;
192
GEN T;
193
ulong p;
194
};
195
196
static GEN
197
_FlxqE_dbl(void *E, GEN P)
198
{
199
struct _FlxqE *ell = (struct _FlxqE *) E;
200
return FlxqE_dbl(P, ell->a4, ell->T, ell->p);
201
}
202
203
static GEN
204
_FlxqE_add(void *E, GEN P, GEN Q)
205
{
206
struct _FlxqE *ell=(struct _FlxqE *) E;
207
return FlxqE_add(P, Q, ell->a4, ell->T, ell->p);
208
}
209
210
static GEN
211
_FlxqE_mul(void *E, GEN P, GEN n)
212
{
213
pari_sp av = avma;
214
struct _FlxqE *e=(struct _FlxqE *) E;
215
long s = signe(n);
216
if (!s || ell_is_inf(P)) return ellinf();
217
if (s<0) P = FlxqE_neg(P, e->T, e->p);
218
if (is_pm1(n)) return s>0? gcopy(P): P;
219
return gerepilecopy(av, gen_pow_i(P, n, e, &_FlxqE_dbl, &_FlxqE_add));
220
}
221
222
GEN
223
FlxqE_mul(GEN P, GEN n, GEN a4, GEN T, ulong p)
224
{
225
struct _FlxqE E;
226
E.a4= a4; E.T = T; E.p = p;
227
return _FlxqE_mul(&E, P, n);
228
}
229
230
/* 3*x^2+2*a2*x = -a2*x, and a2!=0 */
231
232
/* Finds a random nonsingular point on E */
233
static GEN
234
random_F3xqE(GEN a2, GEN a6, GEN T)
235
{
236
pari_sp ltop = avma;
237
GEN x, y, rhs;
238
const ulong p = 3;
239
do
240
{
241
set_avma(ltop);
242
x = random_Flx(get_Flx_degree(T),get_Flx_var(T),p);
243
rhs = Flx_add(Flxq_mul(Flxq_sqr(x, T, p), Flx_add(x, a2, p), T, p), a6, p);
244
} while ((!lgpol(rhs) && !lgpol(x)) || !Flxq_issquare(rhs, T, p));
245
y = Flxq_sqrt(rhs, T, p);
246
if (!y) pari_err_PRIME("random_F3xqE", T);
247
return gerepilecopy(ltop, mkvec2(x, y));
248
}
249
250
/* Finds a random nonsingular point on E */
251
GEN
252
random_FlxqE(GEN a4, GEN a6, GEN T, ulong p)
253
{
254
pari_sp ltop = avma;
255
GEN x, x2, y, rhs;
256
if (typ(a4)==t_VEC)
257
return random_F3xqE(gel(a4,1), a6, T);
258
do
259
{
260
set_avma(ltop);
261
x = random_Flx(get_Flx_degree(T),get_Flx_var(T),p);
262
x2 = Flxq_sqr(x, T, p); /* x^3+a4*x+a6 = x*(x^2+a4)+a6 */
263
rhs = Flx_add(Flxq_mul(x, Flx_add(x2, a4, p), T, p), a6, p);
264
} while ((!lgpol(rhs) && !lgpol(Flx_add(Flx_triple(x2, p), a4, p)))
265
|| !Flxq_issquare(rhs, T, p));
266
y = Flxq_sqrt(rhs, T, p);
267
if (!y) pari_err_PRIME("random_FlxqE", T);
268
return gerepilecopy(ltop, mkvec2(x, y));
269
}
270
271
static GEN
272
_FlxqE_rand(void *E)
273
{
274
struct _FlxqE *ell=(struct _FlxqE *) E;
275
return random_FlxqE(ell->a4, ell->a6, ell->T, ell->p);
276
}
277
278
static const struct bb_group FlxqE_group={_FlxqE_add,_FlxqE_mul,_FlxqE_rand,hash_GEN,zvV_equal,ell_is_inf, NULL};
279
280
const struct bb_group *
281
get_FlxqE_group(void ** pt_E, GEN a4, GEN a6, GEN T, ulong p)
282
{
283
struct _FlxqE *e = (struct _FlxqE *) stack_malloc(sizeof(struct _FlxqE));
284
e->a4 = a4; e->a6 = a6; e->T = Flx_get_red(T, p); e->p = p;
285
*pt_E = (void *) e;
286
return &FlxqE_group;
287
}
288
289
GEN
290
FlxqE_order(GEN z, GEN o, GEN a4, GEN T, ulong p)
291
{
292
pari_sp av = avma;
293
struct _FlxqE e;
294
e.a4=a4; e.T=T; e.p=p;
295
return gerepileuptoint(av, gen_order(z, o, (void*)&e, &FlxqE_group));
296
}
297
298
GEN
299
FlxqE_log(GEN a, GEN b, GEN o, GEN a4, GEN T, ulong p)
300
{
301
pari_sp av = avma;
302
struct _FlxqE e;
303
e.a4=a4; e.T=T; e.p=p;
304
return gerepileuptoint(av, gen_PH_log(a, b, o, (void*)&e, &FlxqE_group));
305
}
306
307
/***********************************************************************/
308
/** **/
309
/** Pairings **/
310
/** **/
311
/***********************************************************************/
312
313
/* Derived from APIP from and by Jerome Milan, 2012 */
314
315
static GEN
316
FlxqE_vert(GEN P, GEN Q, GEN a4, GEN T, ulong p)
317
{
318
long vT = get_Flx_var(T);
319
GEN df;
320
if (ell_is_inf(P))
321
return pol1_Flx(vT);
322
if (!Flx_equal(gel(Q, 1), gel(P, 1)))
323
return Flx_sub(gel(Q, 1), gel(P, 1), p);
324
if (lgpol(gel(P,2))!=0) return pol1_Flx(vT);
325
df = typ(a4)==t_VEC ? Flxq_mul(gel(P,1), Flx_mulu(gel(a4, 1), 2, p), T, p)
326
: a4;
327
return Flxq_inv(Flx_add(Flx_mulu(Flxq_sqr(gel(P,1), T, p), 3, p),
328
df, p), T, p);
329
}
330
331
static GEN
332
FlxqE_Miller_line(GEN R, GEN Q, GEN slope, GEN a4, GEN T, ulong p)
333
{
334
long vT = get_Flx_var(T);
335
GEN x = gel(Q, 1), y = gel(Q, 2);
336
GEN tmp1 = Flx_sub(x, gel(R, 1), p);
337
GEN tmp2 = Flx_add(Flxq_mul(tmp1, slope, T, p), gel(R, 2), p);
338
if (!Flx_equal(y, tmp2))
339
return Flx_sub(y, tmp2, p);
340
if (lgpol(y) == 0)
341
return pol1_Flx(vT);
342
else
343
{
344
GEN s1, s2, a2 = typ(a4)==t_VEC ? gel(a4,1): NULL;
345
GEN y2i = Flxq_inv(Flx_mulu(y, 2, p), T, p);
346
GEN df = a2 ? Flxq_mul(x, Flx_mulu(a2, 2, p), T, p): a4;
347
GEN x3, ddf;
348
s1 = Flxq_mul(Flx_add(Flx_mulu(Flxq_sqr(x, T, p), 3, p), df, p), y2i, T, p);
349
if (!Flx_equal(s1, slope))
350
return Flx_sub(s1, slope, p);
351
x3 = Flx_mulu(x, 3, p);
352
ddf = a2 ? Flx_add(x3, a2, p): x3;
353
s2 = Flxq_mul(Flx_sub(ddf, Flxq_sqr(s1, T, p), p), y2i, T, p);
354
return lgpol(s2)!=0 ? s2: y2i;
355
}
356
}
357
358
/* Computes the equation of the line tangent to R and returns its
359
* evaluation at the point Q. Also doubles the point R. */
360
static GEN
361
FlxqE_tangent_update(GEN R, GEN Q, GEN a4, GEN T, ulong p, GEN *pt_R)
362
{
363
if (ell_is_inf(R))
364
{
365
*pt_R = ellinf();
366
return pol1_Flx(get_Flx_var(T));
367
}
368
else if (!lgpol(gel(R,2)))
369
{
370
*pt_R = ellinf();
371
return FlxqE_vert(R, Q, a4, T, p);
372
} else {
373
GEN slope;
374
*pt_R = FlxqE_dbl_slope(R, a4, T, p, &slope);
375
return FlxqE_Miller_line(R, Q, slope, a4, T, p);
376
}
377
}
378
379
/* Computes the equation of the line through R and P, and returns its
380
* evaluation at the point Q. Also adds P to the point R. */
381
static GEN
382
FlxqE_chord_update(GEN R, GEN P, GEN Q, GEN a4, GEN T, ulong p, GEN *pt_R)
383
{
384
if (ell_is_inf(R))
385
{
386
*pt_R = gcopy(P);
387
return FlxqE_vert(P, Q, a4, T, p);
388
}
389
else if (ell_is_inf(P))
390
{
391
*pt_R = gcopy(R);
392
return FlxqE_vert(R, Q, a4, T, p);
393
}
394
else if (Flx_equal(gel(P, 1), gel(R, 1)))
395
{
396
if (Flx_equal(gel(P, 2), gel(R, 2)))
397
return FlxqE_tangent_update(R, Q, a4, T, p, pt_R);
398
else
399
{
400
*pt_R = ellinf();
401
return FlxqE_vert(R, Q, a4, T, p);
402
}
403
} else {
404
GEN slope;
405
*pt_R = FlxqE_add_slope(P, R, a4, T, p, &slope);
406
return FlxqE_Miller_line(R, Q, slope, a4, T, p);
407
}
408
}
409
410
struct _FlxqE_miller
411
{
412
ulong p;
413
GEN T, a4, P;
414
};
415
416
static GEN
417
FlxqE_Miller_dbl(void* E, GEN d)
418
{
419
struct _FlxqE_miller *m = (struct _FlxqE_miller *)E;
420
ulong p = m->p;
421
GEN T = m->T, a4 = m->a4, P = m->P;
422
GEN v, line, point = gel(d,3);
423
GEN N = Flxq_sqr(gel(d,1), T, p);
424
GEN D = Flxq_sqr(gel(d,2), T, p);
425
line = FlxqE_tangent_update(point, P, a4, T, p, &point);
426
N = Flxq_mul(N, line, T, p);
427
v = FlxqE_vert(point, P, a4, T, p);
428
D = Flxq_mul(D, v, T, p); return mkvec3(N, D, point);
429
}
430
431
static GEN
432
FlxqE_Miller_add(void* E, GEN va, GEN vb)
433
{
434
struct _FlxqE_miller *m = (struct _FlxqE_miller *)E;
435
ulong p = m->p;
436
GEN T = m->T, a4 = m->a4, P = m->P;
437
GEN v, line, point;
438
GEN na = gel(va,1), da = gel(va,2), pa = gel(va,3);
439
GEN nb = gel(vb,1), db = gel(vb,2), pb = gel(vb,3);
440
GEN N = Flxq_mul(na, nb, T, p);
441
GEN D = Flxq_mul(da, db, T, p);
442
line = FlxqE_chord_update(pa, pb, P, a4, T, p, &point);
443
N = Flxq_mul(N, line, T, p);
444
v = FlxqE_vert(point, P, a4, T, p);
445
D = Flxq_mul(D, v, T, p); return mkvec3(N, D, point);
446
}
447
448
/* Returns the Miller function f_{m, Q} evaluated at the point P using
449
* the standard Miller algorithm. */
450
static GEN
451
FlxqE_Miller(GEN Q, GEN P, GEN m, GEN a4, GEN T, ulong p)
452
{
453
pari_sp av = avma;
454
struct _FlxqE_miller d;
455
GEN v, N, D, g1;
456
457
d.a4 = a4; d.T = T; d.p = p; d.P = P;
458
g1 = pol1_Flx(get_Flx_var(T));
459
v = gen_pow_i(mkvec3(g1,g1,Q), m, (void*)&d,
460
FlxqE_Miller_dbl, FlxqE_Miller_add);
461
N = gel(v,1); D = gel(v,2);
462
return gerepileupto(av, Flxq_div(N, D, T, p));
463
}
464
465
GEN
466
FlxqE_weilpairing(GEN P, GEN Q, GEN m, GEN a4, GEN T, ulong p)
467
{
468
pari_sp av = avma;
469
GEN N, D, result;
470
if (ell_is_inf(P) || ell_is_inf(Q)
471
|| (Flx_equal(gel(P,1),gel(Q,1)) && Flx_equal(gel(P,2),gel(Q,2))))
472
return pol1_Flx(get_Flx_var(T));
473
N = FlxqE_Miller(P, Q, m, a4, T, p);
474
D = FlxqE_Miller(Q, P, m, a4, T, p);
475
result = Flxq_div(N, D, T, p);
476
if (mpodd(m)) result = Flx_neg(result, p);
477
return gerepileupto(av, result);
478
}
479
480
GEN
481
FlxqE_tatepairing(GEN P, GEN Q, GEN m, GEN a4, GEN T, ulong p)
482
{
483
if (ell_is_inf(P) || ell_is_inf(Q)) return pol1_Flx(get_Flx_var(T));
484
return FlxqE_Miller(P, Q, m, a4, T, p);
485
}
486
487
static GEN
488
_FlxqE_pairorder(void *E, GEN P, GEN Q, GEN m, GEN F)
489
{
490
struct _FlxqE *e = (struct _FlxqE *) E;
491
return Flxq_order(FlxqE_weilpairing(P,Q,m,e->a4,e->T,e->p), F, e->T, e->p);
492
}
493
494
GEN
495
Flxq_ellgroup(GEN a4, GEN a6, GEN N, GEN T, ulong p, GEN *pt_m)
496
{
497
struct _FlxqE e;
498
GEN q = powuu(p, get_Flx_degree(T));
499
e.a4=a4; e.a6=a6; e.T=T; e.p=p;
500
return gen_ellgroup(N, subiu(q,1), pt_m, (void*)&e, &FlxqE_group, _FlxqE_pairorder);
501
}
502
503
GEN
504
Flxq_ellgens(GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN T, ulong p)
505
{
506
GEN P;
507
pari_sp av = avma;
508
struct _FlxqE e;
509
e.a4=a4; e.a6=a6; e.T=T; e.p=p;
510
switch(lg(D)-1)
511
{
512
case 0:
513
return cgetg(1,t_VEC);
514
case 1:
515
P = gen_gener(gel(D,1), (void*)&e, &FlxqE_group);
516
P = mkvec(FlxqE_changepoint(P, ch, T, p));
517
break;
518
default:
519
P = gen_ellgens(gel(D,1), gel(D,2), m, (void*)&e, &FlxqE_group, _FlxqE_pairorder);
520
gel(P,1) = FlxqE_changepoint(gel(P,1), ch, T, p);
521
gel(P,2) = FlxqE_changepoint(gel(P,2), ch, T, p);
522
break;
523
}
524
return gerepilecopy(av, P);
525
}
526
/***********************************************************************/
527
/** **/
528
/** Point counting **/
529
/** **/
530
/***********************************************************************/
531
532
/* assume a and n are coprime */
533
static GEN
534
RgX_circular_shallow(GEN P, long a, long n)
535
{
536
long i, l = lgpol(P);
537
GEN Q = cgetg(2+n,t_POL);
538
Q[1] = P[1];
539
for(i=0; i<l; i++)
540
gel(Q,2+(i*a)%n) = gel(P,2+i);
541
for( ; i<n; i++)
542
gel(Q,2+(i*a)%n) = gen_0;
543
return normalizepol_lg(Q,2+n);
544
}
545
546
static GEN
547
ZpXQ_frob_cyc(GEN x, GEN T, GEN q, ulong p)
548
{
549
long n = get_FpX_degree(T);
550
return FpX_rem(RgX_circular_shallow(x,p,n+1), T, q);
551
}
552
553
static GEN
554
ZpXQ_frob(GEN x, GEN Xm, GEN T, GEN q, ulong p)
555
{
556
if (lg(Xm)==1)
557
return ZpXQ_frob_cyc(x, T, q, p);
558
else
559
{
560
long n = get_FpX_degree(T);
561
GEN V = RgX_blocks(RgX_inflate(x, p), n, p);
562
GEN W = ZXV_dotproduct(V, Xm);
563
return FpX_rem(W, T, q);
564
}
565
}
566
567
struct _lift_lin
568
{
569
ulong p;
570
GEN sqx, Tp;
571
GEN ai, Xm;
572
};
573
574
static GEN _lift_invl(void *E, GEN x)
575
{
576
struct _lift_lin *d = (struct _lift_lin *) E;
577
GEN T = d->Tp;
578
ulong p = d->p;
579
GEN xai = Flxq_mul(ZX_to_Flx(x, p), d->ai, T, p);
580
return Flx_to_ZX(Flxq_lroot_fast(xai, d->sqx, T, p));
581
}
582
583
static GEN _lift_lin(void *E, GEN F, GEN x2, GEN q)
584
{
585
struct _lift_lin *d = (struct _lift_lin *) E;
586
pari_sp av = avma;
587
GEN T = gel(F,3), Xm = gel(F,4);
588
GEN y2 = ZpXQ_frob(x2, Xm, T, q, d->p);
589
GEN lin = FpX_add(ZX_mul(gel(F,1), y2), ZX_mul(gel(F,2), x2), q);
590
return gerepileupto(av, FpX_rem(lin, T, q));
591
}
592
593
static GEN
594
FpM_FpXV_bilinear(GEN P, GEN X, GEN Y, GEN p)
595
{
596
pari_sp av = avma;
597
GEN s = ZX_mul(FpXV_FpC_mul(X,gel(P,1),p),gel(Y,1));
598
long i, l = lg(P);
599
for(i=2; i<l; i++)
600
s = ZX_add(s, ZX_mul(FpXV_FpC_mul(X,gel(P,i),p),gel(Y,i)));
601
return gerepileupto(av, FpX_red(s, p));
602
}
603
604
static GEN
605
FpM_FpXQV_bilinear(GEN P, GEN X, GEN Y, GEN T, GEN p)
606
{
607
return FpX_rem(FpM_FpXV_bilinear(P,X,Y,p),T,p);
608
}
609
610
static GEN
611
FpXC_powderiv(GEN M, GEN p)
612
{
613
long i, l;
614
long v = varn(gel(M,2));
615
GEN m = cgetg_copy(M, &l);
616
gel(m,1) = pol_0(v);
617
gel(m,2) = pol_1(v);
618
for(i=2; i<l-1; i++)
619
gel(m,i+1) = FpX_Fp_mul(gel(M,i),utoi(i), p);
620
return m;
621
}
622
623
struct _lift_iso
624
{
625
GEN phi;
626
GEN Xm,T;
627
GEN sqx, Tp;
628
ulong p;
629
};
630
631
static GEN
632
_lift_iter(void *E, GEN x2, GEN q)
633
{
634
struct _lift_iso *d = (struct _lift_iso *) E;
635
ulong p = d->p;
636
long n = lg(d->phi)-2;
637
GEN TN = FpXT_red(d->T, q), XN = FpXV_red(d->Xm, q);
638
GEN y2 = ZpXQ_frob(x2, XN, TN, q, p);
639
GEN xp = FpXQ_powers(x2, n, TN, q);
640
GEN yp = FpXQ_powers(y2, n, TN, q);
641
GEN V = FpM_FpXQV_bilinear(d->phi,xp,yp,TN,q);
642
return mkvec3(V,xp,yp);
643
}
644
645
static GEN
646
_lift_invd(void *E, GEN V, GEN v, GEN qM, long M)
647
{
648
struct _lift_iso *d = (struct _lift_iso *) E;
649
struct _lift_lin e;
650
ulong p = d->p;
651
GEN TM = FpXT_red(d->T, qM), XM = FpXV_red(d->Xm, qM);
652
GEN xp = FpXV_red(gel(v,2), qM);
653
GEN yp = FpXV_red(gel(v,3), qM);
654
GEN Dx = FpM_FpXQV_bilinear(d->phi, FpXC_powderiv(xp, qM), yp, TM, qM);
655
GEN Dy = FpM_FpXQV_bilinear(d->phi, xp, FpXC_powderiv(yp, qM), TM, qM);
656
GEN F = mkvec4(Dy, Dx, TM, XM);
657
e.ai = Flxq_inv(ZX_to_Flx(Dy,p),d->Tp,p);
658
e.sqx = d->sqx; e.Tp = d->Tp; e.p=p; e.Xm = XM;
659
return gen_ZpX_Dixon(F,V,qM,utoipos(p),M,(void*) &e, _lift_lin, _lift_invl);
660
}
661
662
static GEN
663
lift_isogeny(GEN phi, GEN x0, long n, GEN Xm, GEN T, GEN sqx, GEN Tp, ulong p)
664
{
665
struct _lift_iso d;
666
d.phi=phi;
667
d.Xm=Xm; d.T=T;
668
d.sqx=sqx; d.Tp=Tp; d.p=p;
669
return gen_ZpX_Newton(x0, utoipos(p), n,(void*)&d, _lift_iter, _lift_invd);
670
}
671
672
static GEN
673
getc2(GEN act, GEN X, GEN T, GEN q, ulong p, long N)
674
{
675
GEN A1 = RgV_to_RgX(gel(act,1),0), A2 = RgV_to_RgX(gel(act,2),0);
676
long n = brent_kung_optpow(maxss(degpol(A1),degpol(A2)),2,1);
677
GEN xp = FpXQ_powers(X,n,T,q);
678
GEN P = FpX_FpXQV_eval(A1, xp, T, q);
679
GEN Q = FpX_FpXQV_eval(A2, xp, T, q);
680
return ZpXQ_div(P, Q, T, q, utoipos(p), N);
681
}
682
683
struct _ZpXQ_norm
684
{
685
long n;
686
GEN T, p;
687
};
688
689
static GEN
690
ZpXQ_norm_mul(void *E, GEN x, GEN y)
691
{
692
struct _ZpXQ_norm *D = (struct _ZpXQ_norm*)E;
693
GEN P = gel(x,1), Q = gel(y,1);
694
long a = mael(x,2,1), b = mael(y,2,1);
695
retmkvec2(FpXQ_mul(P,ZpXQ_frob_cyc(Q, D->T, D->p, a), D->T, D->p),
696
mkvecsmall((a*b)%D->n));
697
}
698
699
static GEN
700
ZpXQ_norm_sqr(void *E, GEN x)
701
{
702
return ZpXQ_norm_mul(E, x, x);
703
}
704
705
/* Assume T = Phi_(n) and n prime */
706
GEN
707
ZpXQ_norm_pcyc(GEN x, GEN T, GEN q, GEN p)
708
{
709
GEN z;
710
struct _ZpXQ_norm D;
711
long d = get_FpX_degree(T);
712
D.T = T; D.p = q; D.n = d+1;
713
if (d==1) return ZX_copy(x);
714
z = mkvec2(x,mkvecsmall(p[2]));
715
z = gen_powu_i(z,d,(void*)&D,ZpXQ_norm_sqr,ZpXQ_norm_mul);
716
return gmael(z,1,2);
717
}
718
719
/* Assume T = Phi_(n) and n prime */
720
static GEN
721
ZpXQ_sqrtnorm_pcyc(GEN x, GEN T, GEN q, GEN p, long e)
722
{
723
GEN z = ZpXQ_norm_pcyc(x, T, q, p);
724
return Zp_sqrtlift(z,Fp_sqrt(z,p),p,e);
725
}
726
727
/* Assume a = 1 [p], return the square root of the norm */
728
static GEN
729
ZpXQ_sqrtnorm(GEN a, GEN T, GEN q, GEN p, long e)
730
{
731
GEN s = Fp_div(FpXQ_trace(ZpXQ_log(a, T, p, e), T, q), gen_2, q);
732
return modii(gel(Qp_exp(cvtop(s, p, e-1)),4), q);
733
}
734
735
struct _teich_lin
736
{
737
ulong p;
738
GEN sqx, Tp;
739
long m;
740
};
741
742
static GEN
743
_teich_invl(void *E, GEN x)
744
{
745
struct _teich_lin *d = (struct _teich_lin *) E;
746
ulong p = d->p;
747
GEN T = d->Tp;
748
return Flx_to_ZX(Flxq_lroot_fast(ZX_to_Flx(x, p), d->sqx, T, p));
749
}
750
751
static GEN
752
_teich_lin(void *E, GEN F, GEN x2, GEN q)
753
{
754
struct _teich_lin *d = (struct _teich_lin *) E;
755
pari_sp av = avma;
756
GEN T = gel(F,2), Xm = gel(F,3);
757
GEN y2 = ZpXQ_frob(x2, Xm, T, q, d->p);
758
GEN lin = FpX_sub(y2, ZX_mulu(ZX_mul(gel(F,1), x2), d->p), q);
759
return gerepileupto(av, FpX_rem(lin, T, q));
760
}
761
762
struct _teich_iso
763
{
764
GEN Xm, T;
765
GEN sqx, Tp;
766
ulong p;
767
};
768
769
static GEN
770
_teich_iter(void *E, GEN x2, GEN q)
771
{
772
struct _teich_iso *d = (struct _teich_iso *) E;
773
ulong p = d->p;
774
GEN TN = FpXT_red(d->T, q), XN = FpXV_red(d->Xm, q);
775
GEN y2 = ZpXQ_frob(x2, XN, TN, q, d->p);
776
GEN x1 = FpXQ_powu(x2, p-1, TN, q);
777
GEN xp = FpXQ_mul(x2, x1, TN, q);
778
GEN V = FpX_sub(y2,xp,q);
779
return mkvec2(V,x1);
780
}
781
782
static GEN
783
_teich_invd(void *E, GEN V, GEN v, GEN qM, long M)
784
{
785
struct _teich_iso *d = (struct _teich_iso *) E;
786
struct _teich_lin e;
787
ulong p = d->p;
788
GEN TM = FpXT_red(d->T, qM), XM = FpXV_red(d->Xm, qM);
789
GEN x1 = FpX_red(gel(v,2), qM);
790
GEN F = mkvec3(x1, TM, XM);
791
e.sqx = d->sqx; e.Tp = d->Tp; e.p=p;
792
return gen_ZpX_Dixon(F,V,qM,utoipos(p),M,(void*) &e, _teich_lin, _teich_invl);
793
}
794
795
static GEN
796
Teichmuller_lift(GEN x, GEN Xm, GEN T, GEN sqx, GEN Tp, ulong p, long N)
797
{
798
struct _teich_iso d;
799
d.Xm = Xm; d.T = T; d.sqx = sqx; d.Tp = Tp; d.p = p;
800
return gen_ZpX_Newton(x,utoipos(p), N,(void*)&d, _teich_iter, _teich_invd);
801
}
802
803
static GEN
804
get_norm(GEN a4, GEN a6, GEN T, ulong p, long N)
805
{
806
long sv=T[1];
807
GEN a;
808
if (p==3) a = gel(a4,1);
809
else
810
{
811
GEN P = mkpoln(4, pol1_Flx(sv), pol0_Flx(sv), a4, a6);
812
a = gel(FlxqX_powu(P,p>>1,T,p),2+p-1);
813
}
814
return Zp_sqrtnlift(gen_1,subss(p,1),utoi(Flxq_norm(a,T,p)),utoipos(p), N);
815
}
816
817
static GEN
818
fill_pols(long n, const long *v, long m, const long *vn,
819
const long *vd, GEN *act)
820
{
821
long i, j;
822
long d = upowuu(n,12/(n-1));
823
GEN N, D, M = zeromatcopy(n+1,n+1);
824
gmael(M,1,n+1) = gen_1;
825
for(i=2;i<=n+1;i++)
826
for(j=i-1;j<=n;j++)
827
gmael(M,i,j) = mulis(powuu(d,i-2),v[j-i+1]);
828
N = cgetg(m+1,t_COL);
829
D = cgetg(m+1,t_COL);
830
for(i=1;i<=m;i++)
831
{
832
gel(N,i) = stoi(*vn++);
833
gel(D,i) = stoi(*vd++);
834
}
835
*act = mkmat2(N,D);
836
return M;
837
}
838
839
/*
840
These polynomials were extracted from the ECHIDNA databases
841
available at <http://echidna.maths.usyd.edu.au/echidna/>
842
and computed by David R. Kohel.
843
Return the matrix of the modular polynomial, set act to the parametrization,
844
and set dj to the opposite of the supersingular j-invariant.
845
*/
846
static GEN
847
get_Kohel_polynomials(ulong p, GEN *act, long *dj)
848
{
849
const long mat3[] = {-1,-36,-270};
850
const long num3[] = {1,-483,-21141,-59049};
851
const long den3[] = {1,261, 4347, -6561};
852
const long mat5[] = {-1,-30,-315,-1300,-1575};
853
const long num5[] = {-1,490,20620,158750,78125};
854
const long den5[] = {-1,-254,-4124,-12250,3125};
855
const long mat7[] = {-1,-28,-322,-1904,-5915,-8624,-4018};
856
const long num7[] = {1,-485,-24058,-343833,-2021642,-4353013,-823543};
857
const long den7[] = {1,259,5894,49119,168406,166355,-16807};
858
const long mat13[]= {-1,-26,-325,-2548,-13832,-54340,-157118,-333580,-509366,
859
-534820,-354536,-124852,-15145};
860
const long num13[]= {1,-487,-24056,-391463,-3396483,-18047328,-61622301,
861
-133245853,-168395656,-95422301,-4826809};
862
const long den13[]= {1,257,5896,60649,364629,1388256,3396483,5089019,4065464,
863
1069939,-28561};
864
switch(p)
865
{
866
case 3:
867
*dj = 0;
868
return fill_pols(3,mat3,4,num3,den3,act);
869
case 5:
870
*dj = 0;
871
return fill_pols(5,mat5,5,num5,den5,act);
872
case 7:
873
*dj = 1;
874
return fill_pols(7,mat7,7,num7,den7,act);
875
case 13:
876
*dj = 8;
877
return fill_pols(13,mat13,11,num13,den13,act);
878
}
879
*dj=0; *act = NULL; return NULL; /* LCOV_EXCL_LINE */
880
}
881
882
long
883
zx_is_pcyc(GEN T)
884
{
885
long i, n = degpol(T);
886
if (!uisprime(n+1))
887
return 0;
888
for (i=0; i<=n; i++)
889
if (T[i+2]!=1UL)
890
return 0;
891
return 1;
892
}
893
894
static GEN
895
Flxq_ellcard_Kohel(GEN a4, GEN a6, GEN T, ulong p)
896
{
897
pari_sp av = avma, av2;
898
pari_timer ti;
899
long n = get_Flx_degree(T), N = (n+4)/2, dj;
900
GEN q = powuu(p, N);
901
GEN T2, Xm, s1, c2, t, lr;
902
GEN S1, sqx;
903
GEN Nc2, Np;
904
GEN act, phi = get_Kohel_polynomials(p, &act, &dj);
905
long ispcyc = zx_is_pcyc(get_Flx_mod(T));
906
timer_start(&ti);
907
if (!ispcyc)
908
{
909
T2 = Flx_Teichmuller(get_Flx_mod(T),p,N);
910
if (DEBUGLEVEL) timer_printf(&ti,"Teich");
911
} else
912
T2 = Flx_to_ZX(get_Flx_mod(T));
913
T2 = FpX_get_red(T2, q); T = ZXT_to_FlxT(T2, p);
914
av2 = avma;
915
if (DEBUGLEVEL) timer_printf(&ti,"Barrett");
916
if (!ispcyc)
917
{
918
Xm = FpXQ_powers(pol_xn(n,get_FpX_var(T2)),p-1,T2,q);
919
if (DEBUGLEVEL) timer_printf(&ti,"Xm");
920
} else
921
Xm = cgetg(1,t_VEC);
922
s1 = Flxq_inv(Flx_Fl_add(Flxq_ellj(a4,a6,T,p),dj, p),T,p);
923
lr = Flxq_lroot(polx_Flx(get_Flx_var(T)), T, p);
924
sqx = Flxq_powers(lr, p-1, T, p);
925
S1 = lift_isogeny(phi, Flx_to_ZX(s1), N, Xm, T2, sqx, T ,p);
926
if (DEBUGLEVEL) timer_printf(&ti,"Lift isogeny");
927
c2 = getc2(act, S1, T2, q, p, N);
928
if (DEBUGLEVEL) timer_printf(&ti,"c^2");
929
if (p>3 && !ispcyc)
930
{
931
GEN c2p = Flx_to_ZX(Flxq_inv(ZX_to_Flx(c2,p),T,p));
932
GEN tc2 = Teichmuller_lift(c2p,Xm, T2,sqx,T,p,N);
933
if (DEBUGLEVEL) timer_printf(&ti,"Teichmuller/Fq");
934
c2 = FpX_rem(FpX_mul(tc2,c2,q),T2,q);
935
}
936
c2 = gerepileupto(av2, c2);
937
if (DEBUGLEVEL) timer_printf(&ti,"tc2");
938
Nc2 = (ispcyc? ZpXQ_sqrtnorm_pcyc: ZpXQ_sqrtnorm)(c2, T2, q, utoipos(p), N);
939
if (DEBUGLEVEL) timer_printf(&ti,"Norm");
940
Np = get_norm(a4,a6,T,p,N);
941
if (p>3 && ispcyc)
942
{
943
GEN Ncpi = utoi(Fl_inv(umodiu(Nc2,p), p));
944
GEN tNc2 = Zp_sqrtnlift(gen_1, subss(p,1), Ncpi, utoipos(p),N);
945
if (DEBUGLEVEL) timer_printf(&ti,"Teichmuller/Fp");
946
Nc2 = Fp_mul(Nc2,tNc2,q);
947
}
948
t = Fp_center_i(Fp_mul(Nc2,Np,q),q,shifti(q,-1));
949
return gerepileupto(av, subii(addiu(powuu(p,n),1),t));
950
}
951
952
/* Use Damien Robert method */
953
954
static GEN
955
get_trace_Robert(GEN J, GEN phi, GEN Xm, GEN T, GEN q, ulong p, long e)
956
{
957
long n = lg(phi)-2;
958
GEN K = ZpXQ_frob(J, Xm, T, q, p);
959
GEN Jp = FpXQ_powers(J, n, T, q);
960
GEN Kp = FpXQ_powers(K, n, T, q);
961
GEN Jd = FpXC_powderiv(Jp, q);
962
GEN Kd = FpXC_powderiv(Kp, q);
963
GEN Dx = FpM_FpXQV_bilinear(phi, Kd, Jp, T, q);
964
GEN Dy = FpM_FpXQV_bilinear(phi, Kp, Jd, T, q);
965
GEN C = ZpXQ_inv(ZX_divuexact(Dy, p), T, utoi(p), e);
966
return FpX_neg(FpXQ_mul(Dx, C, T, q), q);
967
}
968
969
static GEN
970
Flxq_ellcard_Harley(GEN a4, GEN a6, GEN T, ulong p)
971
{
972
pari_sp av = avma, av2;
973
pari_timer ti;
974
long n = get_Flx_degree(T), N = (n+5)/2;
975
GEN pp = utoipos(p), q = powuu(p, N);
976
GEN T2, j, t, phi;
977
GEN J1,sqx,Xm;
978
GEN c2, tc2, c2p, Nc2, Np;
979
long ispcyc = zx_is_pcyc(get_Flx_mod(T));
980
timer_start(&ti);
981
if (!ispcyc)
982
{
983
T2 = Flx_Teichmuller(get_Flx_mod(T),p,N);
984
if (DEBUGLEVEL) timer_printf(&ti,"Teich");
985
} else
986
T2 = Flx_to_ZX(get_Flx_mod(T));
987
T2 = FpX_get_red(T2, q); T = ZXT_to_FlxT(T2, p);
988
av2 = avma;
989
if (DEBUGLEVEL) timer_printf(&ti,"Barrett");
990
if (!ispcyc)
991
{
992
Xm = FpXQ_powers(pol_xn(n,get_FpX_var(T2)),p-1,T2,q);
993
if (DEBUGLEVEL) timer_printf(&ti,"Xm");
994
} else
995
Xm = cgetg(1,t_VEC);
996
j = Flxq_ellj(a4,a6,T,p);
997
sqx = Flxq_powers(Flxq_lroot(polx_Flx(T[1]), T, p), p-1, T, p);
998
phi = polmodular_ZM(p, 0);
999
if (DEBUGLEVEL) timer_printf(&ti,"phi");
1000
J1 = lift_isogeny(phi, Flx_to_ZX(j), N, Xm, T2,sqx,T,p);
1001
if (DEBUGLEVEL) timer_printf(&ti,"Lift isogeny");
1002
c2 = get_trace_Robert(J1, phi, Xm, T2, q, p, N);
1003
q = diviuexact(q,p); N--;
1004
if (DEBUGLEVEL) timer_printf(&ti,"c^2");
1005
if (!ispcyc)
1006
{
1007
c2p = Flx_to_ZX(Flxq_inv(ZX_to_Flx(c2,p),T,p));
1008
tc2 = Teichmuller_lift(c2p,Xm, T2,sqx,T,p,N);
1009
if (DEBUGLEVEL) timer_printf(&ti,"teichmuller");
1010
c2 = FpX_rem(FpX_mul(tc2,c2,q),T2,q);
1011
}
1012
c2 = gerepileupto(av2, c2);
1013
q = powuu(p, N);
1014
Nc2 = (ispcyc? ZpXQ_sqrtnorm_pcyc: ZpXQ_sqrtnorm)(c2, T2, q, pp, N);
1015
if (DEBUGLEVEL) timer_printf(&ti,"Norm");
1016
Np = get_norm(a4,a6,T,p,N);
1017
if (ispcyc)
1018
{
1019
GEN Ncpi = utoi(Fl_inv(umodiu(Nc2,p), p));
1020
GEN tNc2 = Zp_sqrtnlift(gen_1, subss(p,1), Ncpi, pp, N);
1021
if (DEBUGLEVEL) timer_printf(&ti,"Teichmuller/Fp");
1022
Nc2 = Fp_mul(Nc2,tNc2,q);
1023
}
1024
t = Fp_center_i(Fp_mul(Nc2,Np,q),q,shifti(q,-1));
1025
return gerepileupto(av, subii(addiu(powuu(p,n),1),t));
1026
}
1027
1028
/***************************************************************************/
1029
/* */
1030
/* Shanks Mestre */
1031
/* */
1032
/***************************************************************************/
1033
1034
/* Return the lift of a (mod b), which is closest to h */
1035
static GEN
1036
closest_lift(GEN a, GEN b, GEN h)
1037
{
1038
return addii(a, mulii(b, diviiround(subii(h,a), b)));
1039
}
1040
1041
static GEN
1042
FlxqE_find_order(GEN f, GEN h, GEN bound, GEN B, GEN a4, GEN T, ulong p)
1043
{
1044
pari_sp av = avma, av1;
1045
pari_timer Ti;
1046
long s = itos( gceil(gsqrt(gdiv(bound,B),DEFAULTPREC)) ) >> 1;
1047
GEN tx, ti;
1048
GEN fh = FlxqE_mul(f, h, a4, T, p);
1049
GEN F, P = fh, fg;
1050
long i;
1051
if (DEBUGLEVEL >= 6) timer_start(&Ti);
1052
if (ell_is_inf(fh)) return h;
1053
F = FlxqE_mul(f, B, a4, T, p);
1054
if (s < 3)
1055
{ /* we're nearly done: naive search */
1056
GEN Q = P;
1057
for (i=1;; i++)
1058
{
1059
P = FlxqE_add(P, F, a4, T, p); /* h.f + i.F */
1060
if (ell_is_inf(P)) return gerepileupto(av, addii(h, mului(i,B)));
1061
Q = FlxqE_sub(Q, F, a4, T, p); /* h.f - i.F */
1062
if (ell_is_inf(Q)) return gerepileupto(av, subii(h, mului(i,B)));
1063
}
1064
}
1065
tx = cgetg(s+1,t_VECSMALL);
1066
/* Baby Step/Giant Step */
1067
av1 = avma;
1068
for (i=1; i<=s; i++)
1069
{ /* baby steps */
1070
tx[i] = hash_GEN(gel(P, 1));
1071
P = FlxqE_add(P, F, a4, T, p); /* h.f + i.F */
1072
if (ell_is_inf(P)) return gerepileupto(av, addii(h, mului(i,B)));
1073
if (gc_needed(av1,3))
1074
{
1075
if(DEBUGMEM>1) pari_warn(warnmem,"[Flxq_ellcard] baby steps, i=%ld",i);
1076
P = gerepileupto(av1,P);
1077
}
1078
}
1079
if (DEBUGLEVEL >= 6) timer_printf(&Ti, "[Flxq_ellcard] baby steps, s = %ld",s);
1080
/* giant steps: fg = s.F */
1081
fg = gerepileupto(av1, FlxqE_sub(P, fh, a4, T, p));
1082
if (ell_is_inf(fg)) return gerepileupto(av,mului(s,B));
1083
ti = vecsmall_indexsort(tx); /* = permutation sorting tx */
1084
tx = perm_mul(tx,ti);
1085
if (DEBUGLEVEL >= 6) timer_printf(&Ti, "[Flxq_ellcard] sorting");
1086
av1 = avma;
1087
for (P=fg, i=1; ; i++)
1088
{
1089
long k = hash_GEN(gel(P,1));
1090
long r = zv_search(tx, k);
1091
if (r)
1092
{
1093
while (r && tx[r] == k) r--;
1094
for (r++; r <= s && tx[r] == k; r++)
1095
{
1096
long j = ti[r]-1;
1097
GEN Q = FlxqE_add(FlxqE_mul(F, stoi(j), a4, T, p), fh, a4, T, p);
1098
if (DEBUGLEVEL >= 6)
1099
timer_printf(&Ti, "[Flxq_ellcard] giant steps, i = %ld",i);
1100
if (Flx_equal(gel(P,1), gel(Q,1)))
1101
{
1102
if (Flx_equal(gel(P,2), gel(Q,2))) i = -i;
1103
return gerepileupto(av,addii(h, mulii(addis(mulss(s,i), j), B)));
1104
}
1105
}
1106
}
1107
P = FlxqE_add(P,fg,a4,T,p);
1108
if (gc_needed(av1,3))
1109
{
1110
if(DEBUGMEM>1) pari_warn(warnmem,"[Flxq_ellcard] giants steps, i=%ld",i);
1111
P = gerepileupto(av1,P);
1112
}
1113
}
1114
}
1115
1116
static void
1117
Flx_next(GEN t, ulong p)
1118
{
1119
long i;
1120
for(i=2;;i++)
1121
if (uel(t,i)==p-1)
1122
t[i]=0;
1123
else
1124
{
1125
t[i]++;
1126
break;
1127
}
1128
}
1129
1130
static void
1131
Flx_renormalize_ip(GEN x, long lx)
1132
{
1133
long i;
1134
for (i = lx-1; i>=2; i--)
1135
if (x[i]) break;
1136
setlg(x, i+1);
1137
}
1138
1139
static ulong
1140
F3xq_ellcard_naive(GEN a2, GEN a6, GEN T)
1141
{
1142
pari_sp av = avma;
1143
long i, d = get_Flx_degree(T), lx = d+2;
1144
long q = upowuu(3, d), a;
1145
GEN x = zero_zv(lx); x[1] = get_Flx_var(T);
1146
for(a=1, i=0; i<q; i++)
1147
{
1148
GEN rhs;
1149
Flx_renormalize_ip(x, lx);
1150
rhs = Flx_add(Flxq_mul(Flxq_sqr(x, T, 3), Flx_add(x, a2, 3), T, 3), a6, 3);
1151
if (!lgpol(rhs)) a++; else if (Flxq_issquare(rhs, T, 3)) a+=2;
1152
Flx_next(x, 3);
1153
}
1154
set_avma(av);
1155
return a;
1156
}
1157
1158
static ulong
1159
Flxq_ellcard_naive(GEN a4, GEN a6, GEN T, ulong p)
1160
{
1161
pari_sp av = avma;
1162
long i, d = get_Flx_degree(T), lx = d+2;
1163
long q = upowuu(p, d), a;
1164
GEN x = zero_zv(lx); x[1] = get_Flx_var(T);
1165
for(a=1, i=0; i<q; i++)
1166
{
1167
GEN x2, rhs;
1168
Flx_renormalize_ip(x, lx);
1169
x2 = Flxq_sqr(x, T, p);
1170
rhs = Flx_add(Flxq_mul(x, Flx_add(x2, a4, p), T, p), a6, p);
1171
if (!lgpol(rhs)) a++; else if (Flxq_issquare(rhs,T,p)) a+=2;
1172
Flx_next(x,p);
1173
}
1174
set_avma(av);
1175
return a;
1176
}
1177
1178
/* assume T irreducible mod p, m = (q-1)/(p-1) */
1179
static long
1180
Flxq_kronecker(GEN x, GEN m, GEN T, ulong p)
1181
{
1182
pari_sp av;
1183
ulong z;
1184
if (lgpol(x) == 0) return 0;
1185
av = avma; z = Flxq_pow(x, m, T, p)[2];
1186
return gc_long(av, krouu(z, p));
1187
}
1188
1189
/* Find x such that kronecker(u = x^3+a4x+a6, p) is KRO.
1190
* Return point [x*u,u^2] on E (KRO=1) / E^twist (KRO=-1) */
1191
static GEN
1192
Flxq_ellpoint(long KRO, GEN a4, GEN a6, GEN m, long n, long vn, GEN T, ulong p)
1193
{
1194
for(;;)
1195
{
1196
GEN x = random_Flx(n,vn,p);
1197
GEN u = Flx_add(a6, Flxq_mul(Flx_add(a4, Flxq_sqr(x,T,p), p), x, T,p), p);
1198
if (Flxq_kronecker(u, m,T,p) == KRO)
1199
return mkvec2(Flxq_mul(u,x, T,p), Flxq_sqr(u, T,p));
1200
}
1201
}
1202
1203
static GEN
1204
Flxq_ellcard_Shanks(GEN a4, GEN a6, GEN q, GEN T, ulong p)
1205
{
1206
pari_sp av = avma;
1207
long vn = get_Flx_var(T), n = get_Flx_degree(T), KRO = -1;
1208
GEN h,f, ta4, A, B, m;
1209
GEN q1p = addiu(q,1), q2p = shifti(q1p, 1);
1210
GEN bound = addiu(sqrti(gmul2n(q,4)), 1); /* ceil( 4sqrt(q) ) */
1211
/* once #E(Flxq) is know mod B >= bound, it is completely determined */
1212
/* how many 2-torsion points ? */
1213
switch(FlxqX_nbroots(mkpoln(4, pol1_Flx(vn), pol0_Flx(vn), a4, a6), T, p))
1214
{
1215
case 3: A = gen_0; B = utoipos(4); break;
1216
case 1: A = gen_0; B = gen_2; break;
1217
default: A = gen_1; B = gen_2; break; /* 0 */
1218
}
1219
m = diviuexact(subiu(powuu(p,n), 1), p-1);
1220
for(;;)
1221
{
1222
h = closest_lift(A, B, q1p);
1223
/* [ux, u^2] is on E_u: y^2 = x^3 + c4 u^2 x + c6 u^3
1224
* E_u isomorphic to E (resp. E') iff KRO = 1 (resp. -1)
1225
* #E(F_p) = p+1 - a_p, #E'(F_p) = p+1 + a_p
1226
*
1227
* #E_u(Flxq) = A (mod B), h is close to #E_u(Flxq) */
1228
KRO = -KRO;
1229
f = Flxq_ellpoint(KRO, a4,a6, m,n,vn, T,p);
1230
1231
ta4 = Flxq_mul(a4, gel(f,2), T, p); /* a4 for E_u */
1232
h = FlxqE_find_order(f, h, bound, B, ta4,T,p);
1233
h = FlxqE_order(f, h, ta4, T, p);
1234
/* h | #E_u(Flxq) = A (mod B) */
1235
A = Z_chinese_all(A, gen_0, B, h, &B);
1236
if (cmpii(B, bound) >= 0) break;
1237
/* not done, update A mod B for the _next_ curve, isomorphic to
1238
* the quadratic twist of this one */
1239
A = remii(subii(q2p,A), B); /* #E(Fq)+#E'(Fq) = 2q+2 */
1240
}
1241
h = closest_lift(A, B, q1p);
1242
return gerepileuptoint(av, KRO == 1? h: subii(q2p,h));
1243
}
1244
1245
static GEN
1246
F3xq_ellcard(GEN a2, GEN a6, GEN T)
1247
{
1248
long n = get_Flx_degree(T);
1249
if (n <= 2)
1250
return utoi(F3xq_ellcard_naive(a2, a6, T));
1251
else
1252
{
1253
GEN q1 = addiu(powuu(3, get_Flx_degree(T)), 1), t;
1254
GEN a = Flxq_div(a6,Flxq_powu(a2,3,T,3),T,3);
1255
if (Flx_equal1(Flxq_powu(a, 8, T, 3)))
1256
{
1257
GEN P = Flxq_minpoly(a,T,3);
1258
long dP = degpol(P); /* dP <= 2 */
1259
ulong q = upowuu(3,dP);
1260
GEN A2 = pol1_Flx(P[1]), A6 = Flx_rem(polx_Flx(P[1]), P, 3);
1261
long tP = q + 1 - F3xq_ellcard_naive(A2, A6, P);
1262
t = elltrace_extension(stoi(tP), n/dP, utoi(q));
1263
if (umodiu(t, 3)!=1) t = negi(t);
1264
return Flx_equal1(a2) || Flxq_issquare(a2,T,3) ? subii(q1,t): addii(q1,t);
1265
}
1266
else return Flxq_ellcard_Kohel(mkvec(a2), a6, T, 3);
1267
}
1268
}
1269
1270
static GEN
1271
Flxq_ellcard_Satoh(GEN a4, GEN a6, GEN j, GEN T, ulong p)
1272
{
1273
long n = get_Flx_degree(T);
1274
if (n <= 2)
1275
return utoi(Flxq_ellcard_naive(a4, a6, T, p));
1276
else
1277
{
1278
GEN jp = Flxq_powu(j, p, T, p);
1279
GEN s = Flx_add(j, jp, p);
1280
if (degpol(s) <= 0)
1281
{ /* it is assumed j not in F_p */
1282
GEN m = Flxq_mul(j, jp, T, p);
1283
if (degpol(m) <= 0)
1284
{
1285
GEN q = sqru(p);
1286
GEN q1 = addiu(powuu(p, get_Flx_degree(T)), 1);
1287
GEN sk = Flx_Fl_add(Flx_neg(j, p), 1728%p, p);
1288
GEN sA4 = Flx_triple(Flxq_mul(sk, j, T, p), p);
1289
GEN u = Flxq_div(a4, sA4, T, p);
1290
ulong ns = lgpol(s) ? Fl_neg(s[2], p): 0UL;
1291
GEN P = mkvecsmall4(T[1], m[2], ns, 1L);
1292
GEN A4, A6, t, tP;
1293
Flxq_ellj_to_a4a6(polx_Flx(T[1]), P, p, &A4, &A6);
1294
tP = addis(q, 1 - Flxq_ellcard_naive(A4, A6, P, p));
1295
t = elltrace_extension(tP, n>>1, q);
1296
return Flxq_is2npower(u, 2, T, p) ? subii(q1,t): addii(q1,t);
1297
}
1298
}
1299
if (p<=7 || p==13 ) return Flxq_ellcard_Kohel(a4, a6, T, p);
1300
else return Flxq_ellcard_Harley(a4, a6, T, p);
1301
}
1302
}
1303
1304
static GEN
1305
Flxq_ellcard_Kedlaya(GEN a4, GEN a6, GEN T, ulong p)
1306
{
1307
pari_sp av = avma;
1308
GEN H = mkpoln(4, gen_1, gen_0, Flx_to_ZX(a4), Flx_to_ZX(a6));
1309
GEN Tp = Flx_to_ZX(get_Flx_mod(T));
1310
long n = degpol(Tp), e = ((p < 16 ? n+1: n)>>1)+1;
1311
GEN M = ZlXQX_hyperellpadicfrobenius(H, Tp, p, e);
1312
GEN N = ZpXQM_prodFrobenius(M, Tp, utoipos(p), e);
1313
GEN q = powuu(p, e);
1314
GEN tp = Fq_add(gcoeff(N,1,1), gcoeff(N,2,2), Tp, q);
1315
GEN t = Fp_center_i(typ(tp)==t_INT ? tp: leading_coeff(tp), q, shifti(q,-1));
1316
return gerepileupto(av, subii(addiu(powuu(p, n), 1), t));
1317
}
1318
1319
GEN
1320
Flxq_ellj(GEN a4, GEN a6, GEN T, ulong p)
1321
{
1322
pari_sp av=avma;
1323
if (p==3)
1324
{
1325
GEN J;
1326
if (typ(a4)!=t_VEC) return pol0_Flx(get_Flx_var(T));
1327
J = Flxq_div(Flxq_powu(gel(a4,1),3, T, p),Flx_neg(a6,p), T, p);
1328
return gerepileuptoleaf(av, J);
1329
}
1330
else
1331
{
1332
pari_sp av=avma;
1333
GEN a43 = Flxq_mul(a4,Flxq_sqr(a4,T,p),T,p);
1334
GEN a62 = Flxq_sqr(a6,T,p);
1335
GEN num = Flx_mulu(a43,6912,p);
1336
GEN den = Flx_add(Flx_mulu(a43,4,p),Flx_mulu(a62,27,p),p);
1337
return gerepileuptoleaf(av, Flxq_div(num, den, T, p));
1338
}
1339
}
1340
1341
void
1342
Flxq_ellj_to_a4a6(GEN j, GEN T, ulong p, GEN *pt_a4, GEN *pt_a6)
1343
{
1344
ulong zagier = 1728 % p;
1345
if (lgpol(j)==0)
1346
{ *pt_a4 = pol0_Flx(T[1]); *pt_a6 =pol1_Flx(T[1]); }
1347
else if (lgpol(j)==1 && uel(j,2) == zagier)
1348
{ *pt_a4 = pol1_Flx(T[1]); *pt_a6 =pol0_Flx(T[1]); }
1349
else
1350
{
1351
GEN k = Flx_Fl_add(Flx_neg(j, p), zagier, p);
1352
GEN kj = Flxq_mul(k, j, T, p);
1353
GEN k2j = Flxq_mul(kj, k, T, p);
1354
*pt_a4 = Flx_triple(kj, p);
1355
*pt_a6 = Flx_double(k2j, p);
1356
}
1357
}
1358
1359
static GEN
1360
F3xq_ellcardj(GEN a4, GEN a6, GEN T, GEN q, long n)
1361
{
1362
const ulong p = 3;
1363
ulong t;
1364
GEN q1 = addiu(q,1);
1365
GEN na4 = Flx_neg(a4,p), ra4;
1366
if (!Flxq_issquare(na4,T,p))
1367
return q1;
1368
ra4 = Flxq_sqrt(na4,T,p);
1369
t = Flxq_trace(Flxq_div(a6,Flxq_mul(na4,ra4,T,p),T,p),T,p);
1370
if (n%2==1)
1371
{
1372
GEN q3;
1373
if (t==0) return q1;
1374
q3 = powuu(p,(n+1)>>1);
1375
return (t==1)^(n%4==1) ? subii(q1,q3): addii(q1,q3);
1376
}
1377
else
1378
{
1379
GEN q22, q2 = powuu(p,n>>1);
1380
GEN W = Flxq_pow(a4,shifti(q,-2),T,p);
1381
long s = (W[2]==1)^(n%4==2);
1382
if (t!=0) return s ? addii(q1,q2): subii(q1, q2);
1383
q22 = shifti(q2,1);
1384
return s ? subii(q1,q22): addii(q1, q22);
1385
}
1386
}
1387
1388
static GEN
1389
Flxq_ellcardj(GEN a4, GEN a6, ulong j, GEN T, GEN q, ulong p, long n)
1390
{
1391
GEN q1 = addiu(q,1);
1392
if (j==0)
1393
{
1394
ulong w;
1395
GEN W, t, N;
1396
if (umodiu(q,6)!=1) return q1;
1397
N = Fp_ffellcard(gen_0,gen_1,q,n,utoipos(p));
1398
t = subii(q1, N);
1399
W = Flxq_pow(a6,diviuexact(shifti(q,-1), 3),T,p);
1400
if (degpol(W)>0) /*p=5 mod 6*/
1401
return Flx_equal1(Flxq_powu(W,3,T,p)) ? addii(q1,shifti(t,-1)):
1402
subii(q1,shifti(t,-1));
1403
w = W[2];
1404
if (w==1) return N;
1405
if (w==p-1) return addii(q1,t);
1406
else /*p=1 mod 6*/
1407
{
1408
GEN u = shifti(t,-1), v = sqrtint(diviuexact(subii(q,sqri(u)),3));
1409
GEN a = addii(u,v), b = shifti(v,1);
1410
if (Fl_powu(w,3,p)==1)
1411
{
1412
if (Fl_add(umodiu(a,p),Fl_mul(w,umodiu(b,p),p),p)==0)
1413
return subii(q1,subii(shifti(b,1),a));
1414
else
1415
return addii(q1,addii(a,b));
1416
}
1417
else
1418
{
1419
if (Fl_sub(umodiu(a,p),Fl_mul(w,umodiu(b,p),p),p)==0)
1420
return subii(q1,subii(a,shifti(b,1)));
1421
else
1422
return subii(q1,addii(a,b));
1423
}
1424
}
1425
} else if (j==1728%p)
1426
{
1427
ulong w;
1428
GEN W, N, t;
1429
if (mod4(q)==3) return q1;
1430
W = Flxq_pow(a4,shifti(q,-2),T,p);
1431
if (degpol(W)>0) return q1; /*p=3 mod 4*/
1432
w = W[2];
1433
N = Fp_ffellcard(gen_1,gen_0,q,n,utoipos(p));
1434
if(w==1) return N;
1435
t = subii(q1, N);
1436
if(w==p-1) return addii(q1, t);
1437
else /*p=1 mod 4*/
1438
{
1439
GEN u = shifti(t,-1), v = sqrtint(subii(q,sqri(u)));
1440
if (Fl_add(umodiu(u,p),Fl_mul(w,umodiu(v,p),p),p)==0)
1441
return subii(q1,shifti(v,1));
1442
else
1443
return addii(q1,shifti(v,1));
1444
}
1445
} else
1446
{
1447
ulong g = Fl_div(j, Fl_sub(1728%p, j, p), p);
1448
GEN l = Flxq_div(Flx_triple(a6,p),Flx_double(a4,p),T,p);
1449
GEN N = Fp_ffellcard(utoi(Fl_triple(g,p)),utoi(Fl_double(g,p)),q,n,utoipos(p));
1450
if (Flxq_issquare(l,T,p)) return N;
1451
return subii(shifti(q1,1),N);
1452
}
1453
}
1454
1455
GEN
1456
Flxq_ellcard(GEN a4, GEN a6, GEN T, ulong p)
1457
{
1458
pari_sp av = avma;
1459
long n = get_Flx_degree(T);
1460
GEN J, r, q = powuu(p, n);
1461
if (typ(a4)==t_VEC)
1462
r = F3xq_ellcard(gel(a4,1), a6, T);
1463
else if (p==3)
1464
r = F3xq_ellcardj(a4, a6, T, q, n);
1465
else if (degpol(a4)<=0 && degpol(a6)<=0)
1466
r = Fp_ffellcard(utoi(Flx_eval(a4,0,p)),utoi(Flx_eval(a6,0,p)),q,n,utoipos(p));
1467
else if (degpol(J=Flxq_ellj(a4,a6,T,p))<=0)
1468
r = Flxq_ellcardj(a4,a6,lgpol(J)?J[2]:0,T,q,p,n);
1469
else if (p <= 7)
1470
r = Flxq_ellcard_Satoh(a4, a6, J, T, p);
1471
else if (cmpis(q,100)<0)
1472
r = utoi(Flxq_ellcard_naive(a4, a6, T, p));
1473
else if (p == 13 || (7*p <= (ulong)10*n && (BITS_IN_LONG==64 || p <= 103)))
1474
r = Flxq_ellcard_Satoh(a4, a6, J, T, p);
1475
else if (p <= (ulong)2*n)
1476
r = Flxq_ellcard_Kedlaya(a4, a6, T, p);
1477
else if (expi(q)<=62)
1478
r = Flxq_ellcard_Shanks(a4, a6, q, T, p);
1479
else
1480
r = Fq_ellcard_SEA(Flx_to_ZX(a4),Flx_to_ZX(a6),q,Flx_to_ZX(T),utoipos(p),0);
1481
return gerepileuptoint(av, r);
1482
}
1483
1484