Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

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

28479 views
License: GPL3
ubuntu2004
1
/* Copyright (C) 2009 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 Fp */
21
22
/***********************************************************************/
23
/** **/
24
/** FpJ **/
25
/** **/
26
/***********************************************************************/
27
28
/* Arithmetic is implemented using Jacobian coordinates, representing
29
* a projective point (x : y : z) on E by [z*x , z^2*y , z]. This is
30
* probably not the fastest representation available for the given
31
* problem, but they're easy to implement and up to 60% faster than
32
* the school-book method used in FpE_mulu().
33
*/
34
35
/*
36
* Cost: 1M + 8S + 1*a + 10add + 1*8 + 2*2 + 1*3.
37
* Source: http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl
38
*/
39
40
GEN
41
FpJ_dbl(GEN P, GEN a4, GEN p)
42
{
43
GEN X1, Y1, Z1;
44
GEN XX, YY, YYYY, ZZ, S, M, T, Q;
45
46
if (signe(gel(P,3)) == 0)
47
return gcopy(P);
48
49
X1 = gel(P,1); Y1 = gel(P,2); Z1 = gel(P,3);
50
51
XX = Fp_sqr(X1, p);
52
YY = Fp_sqr(Y1, p);
53
YYYY = Fp_sqr(YY, p);
54
ZZ = Fp_sqr(Z1, p);
55
S = Fp_mulu(Fp_sub(Fp_sqr(Fp_add(X1, YY, p), p),
56
Fp_add(XX, YYYY, p), p), 2, p);
57
M = Fp_addmul(Fp_mulu(XX, 3, p), a4, Fp_sqr(ZZ, p), p);
58
T = Fp_sub(Fp_sqr(M, p), Fp_mulu(S, 2, p), p);
59
Q = cgetg(4, t_VEC);
60
gel(Q,1) = T;
61
gel(Q,2) = Fp_sub(Fp_mul(M, Fp_sub(S, T, p), p),
62
Fp_mulu(YYYY, 8, p), p);
63
gel(Q,3) = Fp_sub(Fp_sqr(Fp_add(Y1, Z1, p), p),
64
Fp_add(YY, ZZ, p), p);
65
return Q;
66
}
67
68
/*
69
* Cost: 11M + 5S + 9add + 4*2.
70
* Source: http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-add-2007-bl
71
*/
72
73
GEN
74
FpJ_add(GEN P, GEN Q, GEN a4, GEN p)
75
{
76
GEN X1, Y1, Z1, X2, Y2, Z2;
77
GEN Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V, W, R;
78
79
if (signe(gel(Q,3)) == 0) return gcopy(P);
80
if (signe(gel(P,3)) == 0) return gcopy(Q);
81
82
X1 = gel(P,1); Y1 = gel(P,2); Z1 = gel(P,3);
83
X2 = gel(Q,1); Y2 = gel(Q,2); Z2 = gel(Q,3);
84
85
Z1Z1 = Fp_sqr(Z1, p);
86
Z2Z2 = Fp_sqr(Z2, p);
87
U1 = Fp_mul(X1, Z2Z2, p);
88
U2 = Fp_mul(X2, Z1Z1, p);
89
S1 = mulii(Y1, Fp_mul(Z2, Z2Z2, p));
90
S2 = mulii(Y2, Fp_mul(Z1, Z1Z1, p));
91
H = Fp_sub(U2, U1, p);
92
r = Fp_mulu(Fp_sub(S2, S1, p), 2, p);
93
94
/* If points are equal we must double. */
95
if (signe(H)== 0) {
96
if (signe(r) == 0)
97
/* Points are equal so double. */
98
return FpJ_dbl(P, a4, p);
99
else
100
return mkvec3(gen_1, gen_1, gen_0);
101
}
102
I = Fp_sqr(Fp_mulu(H, 2, p), p);
103
J = Fp_mul(H, I, p);
104
V = Fp_mul(U1, I, p);
105
W = Fp_sub(Fp_sqr(r, p), Fp_add(J, Fp_mulu(V, 2, p), p), p);
106
R = cgetg(4, t_VEC);
107
gel(R,1) = W;
108
gel(R,2) = Fp_sub(mulii(r, subii(V, W)),
109
shifti(mulii(S1, J), 1), p);
110
gel(R,3) = Fp_mul(Fp_sub(Fp_sqr(Fp_add(Z1, Z2, p), p),
111
Fp_add(Z1Z1, Z2Z2, p), p), H, p);
112
return R;
113
}
114
115
GEN
116
FpJ_neg(GEN Q, GEN p)
117
{
118
return mkvec3(icopy(gel(Q,1)), Fp_neg(gel(Q,2), p), icopy(gel(Q,3)));
119
}
120
121
GEN
122
FpE_to_FpJ(GEN P)
123
{ return ell_is_inf(P) ? mkvec3(gen_1, gen_1, gen_0):
124
mkvec3(icopy(gel(P,1)),icopy(gel(P,2)), gen_1);
125
}
126
127
GEN
128
FpJ_to_FpE(GEN P, GEN p)
129
{
130
if (signe(gel(P,3)) == 0) return ellinf();
131
else
132
{
133
GEN Z = Fp_inv(gel(P,3), p);
134
GEN Z2 = Fp_sqr(Z, p), Z3 = Fp_mul(Z, Z2, p);
135
retmkvec2(Fp_mul(gel(P,1), Z2, p), Fp_mul(gel(P,2), Z3, p));
136
}
137
}
138
139
struct _FpE { GEN p,a4,a6; };
140
static GEN
141
_FpJ_dbl(void *E, GEN P)
142
{
143
struct _FpE *ell = (struct _FpE *) E;
144
return FpJ_dbl(P, ell->a4, ell->p);
145
}
146
static GEN
147
_FpJ_add(void *E, GEN P, GEN Q)
148
{
149
struct _FpE *ell=(struct _FpE *) E;
150
return FpJ_add(P, Q, ell->a4, ell->p);
151
}
152
static GEN
153
_FpJ_mul(void *E, GEN P, GEN n)
154
{
155
pari_sp av = avma;
156
struct _FpE *e=(struct _FpE *) E;
157
long s = signe(n);
158
if (!s || ell_is_inf(P)) return ellinf();
159
if (s<0) P = FpJ_neg(P, e->p);
160
if (is_pm1(n)) return s>0? gcopy(P): P;
161
return gerepilecopy(av, gen_pow_i(P, n, e, &_FpJ_dbl, &_FpJ_add));
162
}
163
164
GEN
165
FpJ_mul(GEN P, GEN n, GEN a4, GEN p)
166
{
167
struct _FpE E;
168
E.a4= a4; E.p = p;
169
return _FpJ_mul(&E, P, n);
170
}
171
172
/***********************************************************************/
173
/** **/
174
/** FpE **/
175
/** **/
176
/***********************************************************************/
177
178
/* These functions deal with point over elliptic curves over Fp defined
179
* by an equation of the form y^2=x^3+a4*x+a6.
180
* Most of the time a6 is omitted since it can be recovered from any point
181
* on the curve.
182
*/
183
184
GEN
185
RgE_to_FpE(GEN x, GEN p)
186
{
187
if (ell_is_inf(x)) return x;
188
retmkvec2(Rg_to_Fp(gel(x,1),p),Rg_to_Fp(gel(x,2),p));
189
}
190
191
GEN
192
FpE_to_mod(GEN x, GEN p)
193
{
194
if (ell_is_inf(x)) return x;
195
retmkvec2(Fp_to_mod(gel(x,1),p),Fp_to_mod(gel(x,2),p));
196
}
197
198
GEN
199
FpE_changepoint(GEN P, GEN ch, GEN p)
200
{
201
pari_sp av = avma;
202
GEN c, z, u, r, s, t, v, v2, v3;
203
if (ell_is_inf(P)) return P;
204
if (lgefint(p) == 3)
205
{
206
ulong pp = p[2];
207
z = Fle_changepoint(ZV_to_Flv(P, pp), ZV_to_Flv(ch, pp), pp);
208
return gerepileupto(av, Flv_to_ZV(z));
209
}
210
u = gel(ch,1); r = gel(ch,2); s = gel(ch,3); t = gel(ch,4);
211
v = Fp_inv(u, p); v2 = Fp_sqr(v,p); v3 = Fp_mul(v,v2,p);
212
c = Fp_sub(gel(P,1),r,p);
213
z = cgetg(3,t_VEC);
214
gel(z,1) = Fp_mul(v2, c, p);
215
gel(z,2) = Fp_mul(v3, Fp_sub(gel(P,2), Fp_add(Fp_mul(s,c, p),t, p),p),p);
216
return gerepileupto(av, z);
217
}
218
219
GEN
220
FpE_changepointinv(GEN P, GEN ch, GEN p)
221
{
222
GEN u, r, s, t, u2, u3, c, z;
223
if (ell_is_inf(P)) return P;
224
if (lgefint(p) == 3)
225
{
226
ulong pp = p[2];
227
z = Fle_changepointinv(ZV_to_Flv(P, pp), ZV_to_Flv(ch, pp), pp);
228
return Flv_to_ZV(z);
229
}
230
u = gel(ch,1); r = gel(ch,2); s = gel(ch,3); t = gel(ch,4);
231
u2 = Fp_sqr(u, p); u3 = Fp_mul(u,u2,p);
232
c = Fp_mul(u2, gel(P,1), p);
233
z = cgetg(3, t_VEC);
234
gel(z,1) = Fp_add(c,r,p);
235
gel(z,2) = Fp_add(Fp_mul(u3,gel(P,2),p), Fp_add(Fp_mul(s,c,p), t, p), p);
236
return z;
237
}
238
239
static GEN
240
nonsquare_Fp(GEN p)
241
{
242
pari_sp av = avma;
243
GEN a;
244
do
245
{
246
set_avma(av);
247
a = randomi(p);
248
} while (kronecker(a, p) >= 0);
249
return a;
250
}
251
252
void
253
Fp_elltwist(GEN a4, GEN a6, GEN p, GEN *pt_a4, GEN *pt_a6)
254
{
255
GEN d = nonsquare_Fp(p), d2 = Fp_sqr(d, p), d3 = Fp_mul(d2, d, p);
256
*pt_a4 = Fp_mul(a4, d2, p);
257
*pt_a6 = Fp_mul(a6, d3, p);
258
}
259
260
static GEN
261
FpE_dbl_slope(GEN P, GEN a4, GEN p, GEN *slope)
262
{
263
GEN x, y, Q;
264
if (ell_is_inf(P) || !signe(gel(P,2))) return ellinf();
265
x = gel(P,1); y = gel(P,2);
266
*slope = Fp_div(Fp_add(Fp_mulu(Fp_sqr(x,p), 3, p), a4, p),
267
Fp_mulu(y, 2, p), p);
268
Q = cgetg(3,t_VEC);
269
gel(Q, 1) = Fp_sub(Fp_sqr(*slope, p), Fp_mulu(x, 2, p), p);
270
gel(Q, 2) = Fp_sub(Fp_mul(*slope, Fp_sub(x, gel(Q, 1), p), p), y, p);
271
return Q;
272
}
273
274
GEN
275
FpE_dbl(GEN P, GEN a4, GEN p)
276
{
277
pari_sp av = avma;
278
GEN slope;
279
return gerepileupto(av, FpE_dbl_slope(P,a4,p,&slope));
280
}
281
282
static GEN
283
FpE_add_slope(GEN P, GEN Q, GEN a4, GEN p, GEN *slope)
284
{
285
GEN Px, Py, Qx, Qy, R;
286
if (ell_is_inf(P)) return Q;
287
if (ell_is_inf(Q)) return P;
288
Px = gel(P,1); Py = gel(P,2);
289
Qx = gel(Q,1); Qy = gel(Q,2);
290
if (equalii(Px, Qx))
291
{
292
if (equalii(Py, Qy))
293
return FpE_dbl_slope(P, a4, p, slope);
294
else
295
return ellinf();
296
}
297
*slope = Fp_div(Fp_sub(Py, Qy, p), Fp_sub(Px, Qx, p), p);
298
R = cgetg(3,t_VEC);
299
gel(R, 1) = Fp_sub(Fp_sub(Fp_sqr(*slope, p), Px, p), Qx, p);
300
gel(R, 2) = Fp_sub(Fp_mul(*slope, Fp_sub(Px, gel(R, 1), p), p), Py, p);
301
return R;
302
}
303
304
GEN
305
FpE_add(GEN P, GEN Q, GEN a4, GEN p)
306
{
307
pari_sp av = avma;
308
GEN slope;
309
return gerepileupto(av, FpE_add_slope(P,Q,a4,p,&slope));
310
}
311
312
static GEN
313
FpE_neg_i(GEN P, GEN p)
314
{
315
if (ell_is_inf(P)) return P;
316
return mkvec2(gel(P,1), Fp_neg(gel(P,2), p));
317
}
318
319
GEN
320
FpE_neg(GEN P, GEN p)
321
{
322
if (ell_is_inf(P)) return ellinf();
323
return mkvec2(gcopy(gel(P,1)), Fp_neg(gel(P,2), p));
324
}
325
326
GEN
327
FpE_sub(GEN P, GEN Q, GEN a4, GEN p)
328
{
329
pari_sp av = avma;
330
GEN slope;
331
return gerepileupto(av, FpE_add_slope(P, FpE_neg_i(Q, p), a4, p, &slope));
332
}
333
334
static GEN
335
_FpE_dbl(void *E, GEN P)
336
{
337
struct _FpE *ell = (struct _FpE *) E;
338
return FpE_dbl(P, ell->a4, ell->p);
339
}
340
341
static GEN
342
_FpE_add(void *E, GEN P, GEN Q)
343
{
344
struct _FpE *ell=(struct _FpE *) E;
345
return FpE_add(P, Q, ell->a4, ell->p);
346
}
347
348
static GEN
349
_FpE_mul(void *E, GEN P, GEN n)
350
{
351
pari_sp av = avma;
352
struct _FpE *e=(struct _FpE *) E;
353
long s = signe(n);
354
GEN Q;
355
if (!s || ell_is_inf(P)) return ellinf();
356
if (s<0) P = FpE_neg(P, e->p);
357
if (is_pm1(n)) return s>0? gcopy(P): P;
358
if (equalis(n,2)) return _FpE_dbl(E, P);
359
Q = gen_pow_i(FpE_to_FpJ(P), n, e, &_FpJ_dbl, &_FpJ_add);
360
return gerepileupto(av, FpJ_to_FpE(Q, e->p));
361
}
362
363
GEN
364
FpE_mul(GEN P, GEN n, GEN a4, GEN p)
365
{
366
struct _FpE E;
367
E.a4 = a4; E.p = p;
368
return _FpE_mul(&E, P, n);
369
}
370
371
/* Finds a random nonsingular point on E */
372
373
GEN
374
random_FpE(GEN a4, GEN a6, GEN p)
375
{
376
pari_sp ltop = avma;
377
GEN x, x2, y, rhs;
378
do
379
{
380
set_avma(ltop);
381
x = randomi(p); /* x^3+a4*x+a6 = x*(x^2+a4)+a6 */
382
x2 = Fp_sqr(x, p);
383
rhs = Fp_add(Fp_mul(x, Fp_add(x2, a4, p), p), a6, p);
384
} while ((!signe(rhs) && !signe(Fp_add(Fp_mulu(x2,3,p),a4,p)))
385
|| kronecker(rhs, p) < 0);
386
y = Fp_sqrt(rhs, p);
387
if (!y) pari_err_PRIME("random_FpE", p);
388
return gerepilecopy(ltop, mkvec2(x, y));
389
}
390
391
static GEN
392
_FpE_rand(void *E)
393
{
394
struct _FpE *e=(struct _FpE *) E;
395
return random_FpE(e->a4, e->a6, e->p);
396
}
397
398
static const struct bb_group FpE_group={_FpE_add,_FpE_mul,_FpE_rand,hash_GEN,ZV_equal,ell_is_inf,NULL};
399
400
const struct bb_group *
401
get_FpE_group(void ** pt_E, GEN a4, GEN a6, GEN p)
402
{
403
struct _FpE *e = (struct _FpE *) stack_malloc(sizeof(struct _FpE));
404
e->a4 = a4; e->a6 = a6; e->p = p;
405
*pt_E = (void *) e;
406
return &FpE_group;
407
}
408
409
GEN
410
FpE_order(GEN z, GEN o, GEN a4, GEN p)
411
{
412
pari_sp av = avma;
413
struct _FpE e;
414
GEN r;
415
if (lgefint(p) == 3)
416
{
417
ulong pp = p[2];
418
r = Fle_order(ZV_to_Flv(z, pp), o, umodiu(a4,pp), pp);
419
}
420
else
421
{
422
e.a4 = a4;
423
e.p = p;
424
r = gen_order(z, o, (void*)&e, &FpE_group);
425
}
426
return gerepileuptoint(av, r);
427
}
428
429
GEN
430
FpE_log(GEN a, GEN b, GEN o, GEN a4, GEN p)
431
{
432
pari_sp av = avma;
433
struct _FpE e;
434
GEN r;
435
if (lgefint(p) == 3)
436
{
437
ulong pp = p[2];
438
r = Fle_log(ZV_to_Flv(a,pp), ZV_to_Flv(b,pp), o, umodiu(a4,pp), pp);
439
}
440
else
441
{
442
e.a4 = a4;
443
e.p = p;
444
r = gen_PH_log(a, b, o, (void*)&e, &FpE_group);
445
}
446
return gerepileuptoint(av, r);
447
}
448
449
/***********************************************************************/
450
/** **/
451
/** Pairings **/
452
/** **/
453
/***********************************************************************/
454
455
/* Derived from APIP from and by Jerome Milan, 2012 */
456
457
static GEN
458
FpE_vert(GEN P, GEN Q, GEN a4, GEN p)
459
{
460
if (ell_is_inf(P))
461
return gen_1;
462
if (!equalii(gel(Q, 1), gel(P, 1)))
463
return Fp_sub(gel(Q, 1), gel(P, 1), p);
464
if (signe(gel(P,2))!=0) return gen_1;
465
return Fp_inv(Fp_add(Fp_mulu(Fp_sqr(gel(P,1),p), 3, p), a4, p), p);
466
}
467
468
static GEN
469
FpE_Miller_line(GEN R, GEN Q, GEN slope, GEN a4, GEN p)
470
{
471
GEN x = gel(Q, 1), y = gel(Q, 2);
472
GEN tmp1 = Fp_sub(x, gel(R, 1), p);
473
GEN tmp2 = Fp_add(Fp_mul(tmp1, slope, p), gel(R,2), p);
474
if (!equalii(y, tmp2))
475
return Fp_sub(y, tmp2, p);
476
if (signe(y) == 0)
477
return gen_1;
478
else
479
{
480
GEN s1, s2;
481
GEN y2i = Fp_inv(Fp_mulu(y, 2, p), p);
482
s1 = Fp_mul(Fp_add(Fp_mulu(Fp_sqr(x, p), 3, p), a4, p), y2i, p);
483
if (!equalii(s1, slope))
484
return Fp_sub(s1, slope, p);
485
s2 = Fp_mul(Fp_sub(Fp_mulu(x, 3, p), Fp_sqr(s1, p), p), y2i, p);
486
return signe(s2)!=0 ? s2: y2i;
487
}
488
}
489
490
/* Computes the equation of the line tangent to R and returns its
491
evaluation at the point Q. Also doubles the point R.
492
*/
493
494
static GEN
495
FpE_tangent_update(GEN R, GEN Q, GEN a4, GEN p, GEN *pt_R)
496
{
497
if (ell_is_inf(R))
498
{
499
*pt_R = ellinf();
500
return gen_1;
501
}
502
else if (signe(gel(R,2)) == 0)
503
{
504
*pt_R = ellinf();
505
return FpE_vert(R, Q, a4, p);
506
} else {
507
GEN slope;
508
*pt_R = FpE_dbl_slope(R, a4, p, &slope);
509
return FpE_Miller_line(R, Q, slope, a4, p);
510
}
511
}
512
513
/* Computes the equation of the line through R and P, and returns its
514
evaluation at the point Q. Also adds P to the point R.
515
*/
516
517
static GEN
518
FpE_chord_update(GEN R, GEN P, GEN Q, GEN a4, GEN p, GEN *pt_R)
519
{
520
if (ell_is_inf(R))
521
{
522
*pt_R = gcopy(P);
523
return FpE_vert(P, Q, a4, p);
524
}
525
else if (ell_is_inf(P))
526
{
527
*pt_R = gcopy(R);
528
return FpE_vert(R, Q, a4, p);
529
}
530
else if (equalii(gel(P, 1), gel(R, 1)))
531
{
532
if (equalii(gel(P, 2), gel(R, 2)))
533
return FpE_tangent_update(R, Q, a4, p, pt_R);
534
else {
535
*pt_R = ellinf();
536
return FpE_vert(R, Q, a4, p);
537
}
538
} else {
539
GEN slope;
540
*pt_R = FpE_add_slope(P, R, a4, p, &slope);
541
return FpE_Miller_line(R, Q, slope, a4, p);
542
}
543
}
544
545
struct _FpE_miller { GEN p, a4, P; };
546
static GEN
547
FpE_Miller_dbl(void* E, GEN d)
548
{
549
struct _FpE_miller *m = (struct _FpE_miller *)E;
550
GEN p = m->p, a4 = m->a4, P = m->P;
551
GEN v, line;
552
GEN N = Fp_sqr(gel(d,1), p);
553
GEN D = Fp_sqr(gel(d,2), p);
554
GEN point = gel(d,3);
555
line = FpE_tangent_update(point, P, a4, p, &point);
556
N = Fp_mul(N, line, p);
557
v = FpE_vert(point, P, a4, p);
558
D = Fp_mul(D, v, p); return mkvec3(N, D, point);
559
}
560
static GEN
561
FpE_Miller_add(void* E, GEN va, GEN vb)
562
{
563
struct _FpE_miller *m = (struct _FpE_miller *)E;
564
GEN p = m->p, a4= m->a4, P = m->P;
565
GEN v, line, point;
566
GEN na = gel(va,1), da = gel(va,2), pa = gel(va,3);
567
GEN nb = gel(vb,1), db = gel(vb,2), pb = gel(vb,3);
568
GEN N = Fp_mul(na, nb, p);
569
GEN D = Fp_mul(da, db, p);
570
line = FpE_chord_update(pa, pb, P, a4, p, &point);
571
N = Fp_mul(N, line, p);
572
v = FpE_vert(point, P, a4, p);
573
D = Fp_mul(D, v, p); return mkvec3(N, D, point);
574
}
575
576
/* Returns the Miller function f_{m, Q} evaluated at the point P using
577
* the standard Miller algorithm. */
578
static GEN
579
FpE_Miller(GEN Q, GEN P, GEN m, GEN a4, GEN p)
580
{
581
pari_sp av = avma;
582
struct _FpE_miller d;
583
GEN v, N, D;
584
585
d.a4 = a4; d.p = p; d.P = P;
586
v = gen_pow_i(mkvec3(gen_1,gen_1,Q), m, (void*)&d,
587
FpE_Miller_dbl, FpE_Miller_add);
588
N = gel(v,1); D = gel(v,2);
589
return gerepileuptoint(av, Fp_div(N, D, p));
590
}
591
592
GEN
593
FpE_weilpairing(GEN P, GEN Q, GEN m, GEN a4, GEN p)
594
{
595
pari_sp av = avma;
596
GEN N, D, w;
597
if (ell_is_inf(P) || ell_is_inf(Q) || ZV_equal(P,Q)) return gen_1;
598
if (lgefint(p)==3 && lgefint(m)==3)
599
{
600
ulong pp = p[2];
601
GEN Pp = ZV_to_Flv(P, pp), Qp = ZV_to_Flv(Q, pp);
602
ulong w = Fle_weilpairing(Pp, Qp, itou(m), umodiu(a4, pp), pp);
603
set_avma(av); return utoi(w);
604
}
605
N = FpE_Miller(P, Q, m, a4, p);
606
D = FpE_Miller(Q, P, m, a4, p);
607
w = Fp_div(N, D, p);
608
if (mpodd(m)) w = Fp_neg(w, p);
609
return gerepileuptoint(av, w);
610
}
611
612
GEN
613
FpE_tatepairing(GEN P, GEN Q, GEN m, GEN a4, GEN p)
614
{
615
if (ell_is_inf(P) || ell_is_inf(Q)) return gen_1;
616
if (lgefint(p)==3 && lgefint(m)==3)
617
{
618
pari_sp av = avma;
619
ulong pp = p[2];
620
GEN Pp = ZV_to_Flv(P, pp), Qp = ZV_to_Flv(Q, pp);
621
ulong w = Fle_tatepairing(Pp, Qp, itou(m), umodiu(a4, pp), pp);
622
set_avma(av); return utoi(w);
623
}
624
return FpE_Miller(P, Q, m, a4, p);
625
}
626
627
/***********************************************************************/
628
/** **/
629
/** CM by principal order **/
630
/** **/
631
/***********************************************************************/
632
633
/* is jn/jd = J (mod p) */
634
static int
635
is_CMj(long J, GEN jn, GEN jd, GEN p)
636
{ return dvdii(subii(mulis(jd,J), jn), p); }
637
#ifndef LONG_IS_64BIT
638
/* is jn/jd = -(2^32 a + b) (mod p) */
639
static int
640
u2_is_CMj(ulong a, ulong b, GEN jn, GEN jd, GEN p)
641
{
642
GEN mJ = uu32toi(a,b);
643
return dvdii(addii(mulii(jd,mJ), jn), p);
644
}
645
#endif
646
647
static long
648
Fp_ellj_get_CM(GEN jn, GEN jd, GEN p)
649
{
650
#define CHECK(CM,J) if (is_CMj(J,jn,jd,p)) return CM;
651
CHECK(-3, 0);
652
CHECK(-4, 1728);
653
CHECK(-7, -3375);
654
CHECK(-8, 8000);
655
CHECK(-11, -32768);
656
CHECK(-12, 54000);
657
CHECK(-16, 287496);
658
CHECK(-19, -884736);
659
CHECK(-27, -12288000);
660
CHECK(-28, 16581375);
661
CHECK(-43, -884736000);
662
#ifdef LONG_IS_64BIT
663
CHECK(-67, -147197952000L);
664
CHECK(-163, -262537412640768000L);
665
#else
666
if (u2_is_CMj(0x00000022UL,0x45ae8000UL,jn,jd,p)) return -67;
667
if (u2_is_CMj(0x03a4b862UL,0xc4b40000UL,jn,jd,p)) return -163;
668
#endif
669
#undef CHECK
670
return 0;
671
}
672
673
/***********************************************************************/
674
/** **/
675
/** issupersingular **/
676
/** **/
677
/***********************************************************************/
678
679
/* assume x reduced mod p, monic. Return one root, or NULL if irreducible */
680
static GEN
681
FqX_quad_root(GEN x, GEN T, GEN p)
682
{
683
GEN b = gel(x,3), c = gel(x,2);
684
GEN D = Fq_sub(Fq_sqr(b, T, p), Fq_mulu(c,4, T, p), T, p);
685
GEN s = Fq_sqrt(D,T, p);
686
if (!s) return NULL;
687
return Fq_Fp_mul(Fq_sub(s, b, T, p), shifti(addiu(p, 1),-1),T, p);
688
}
689
690
/*
691
* pol is the modular polynomial of level 2 modulo p.
692
*
693
* (T, p) defines the field FF_{p^2} in which j_prev and j live.
694
*/
695
static long
696
path_extends_to_floor(GEN j_prev, GEN j, GEN T, GEN p, GEN Phi2, ulong max_len)
697
{
698
pari_sp ltop = avma;
699
GEN Phi2_j;
700
ulong mult, d;
701
702
/* A path made its way to the floor if (i) its length was cut off
703
* before reaching max_path_len, or (ii) it reached max_path_len but
704
* only has one neighbour. */
705
for (d = 1; d < max_len; ++d) {
706
GEN j_next;
707
708
Phi2_j = FqX_div_by_X_x(FqXY_evalx(Phi2, j, T, p), j_prev, T, p, NULL);
709
j_next = FqX_quad_root(Phi2_j, T, p);
710
if (!j_next)
711
{ /* j is on the floor */
712
set_avma(ltop);
713
return 1;
714
}
715
716
j_prev = j; j = j_next;
717
if (gc_needed(ltop, 2))
718
gerepileall(ltop, 2, &j, &j_prev);
719
}
720
721
/* Check that we didn't end up at the floor on the last step (j will
722
* point to the last element in the path. */
723
Phi2_j = FqX_div_by_X_x(FqXY_evalx(Phi2, j, T, p), j_prev, T, p, NULL);
724
mult = FqX_nbroots(Phi2_j, T, p);
725
set_avma(ltop);
726
return mult == 0;
727
}
728
729
static int
730
jissupersingular(GEN j, GEN S, GEN p)
731
{
732
long max_path_len = expi(p)+1;
733
GEN Phi2 = FpXX_red(polmodular_ZXX(2,0,0,1), p);
734
GEN Phi2_j = FqXY_evalx(Phi2, j, S, p);
735
GEN roots = FpXQX_roots(Phi2_j, S, p);
736
long nbroots = lg(roots)-1;
737
int res = 1;
738
739
/* Every node in a supersingular L-volcano has L + 1 neighbours. */
740
/* Note: a multiple root only occur when j has CM by sqrt(-15). */
741
if (nbroots==0 || (nbroots==1 && FqX_is_squarefree(Phi2_j, S, p)))
742
res = 0;
743
else {
744
long i, l = lg(roots);
745
for (i = 1; i < l; ++i) {
746
if (path_extends_to_floor(j, gel(roots, i), S, p, Phi2, max_path_len)) {
747
res = 0;
748
break;
749
}
750
}
751
}
752
/* If none of the paths reached the floor, then the j-invariant is
753
* supersingular. */
754
return res;
755
}
756
757
int
758
Fp_elljissupersingular(GEN j, GEN p)
759
{
760
pari_sp ltop = avma;
761
long CM;
762
if (abscmpiu(p, 5) <= 0) return signe(j) == 0; /* valid if p <= 5 */
763
CM = Fp_ellj_get_CM(j, gen_1, p);
764
if (CM < 0) return krosi(CM, p) < 0; /* valid if p > 3 */
765
else
766
{
767
GEN S = init_Fq(p, 2, fetch_var());
768
int res = jissupersingular(j, S, p);
769
(void)delete_var(); return gc_bool(ltop, res);
770
}
771
}
772
773
/***********************************************************************/
774
/** **/
775
/** Cardinal **/
776
/** **/
777
/***********************************************************************/
778
779
/*assume a4,a6 reduced mod p odd */
780
static ulong
781
Fl_elltrace_naive(ulong a4, ulong a6, ulong p)
782
{
783
ulong i, j;
784
long a = 0;
785
long d0, d1, d2, d3;
786
GEN k = const_vecsmall(p, -1);
787
k[1] = 0;
788
for (i=1, j=1; i < p; i += 2, j = Fl_add(j, i, p))
789
k[j+1] = 1;
790
d0 = 6%p; d1 = d0; d2 = Fl_add(a4, 1, p); d3 = a6;
791
for(i=0;; i++)
792
{
793
a -= k[1+d3];
794
if (i==p-1) break;
795
d3 = Fl_add(d3, d2, p);
796
d2 = Fl_add(d2, d1, p);
797
d1 = Fl_add(d1, d0, p);
798
}
799
return a;
800
}
801
802
/* z1 <-- z1 + z2, with precomputed inverse */
803
static void
804
FpE_add_ip(GEN z1, GEN z2, GEN a4, GEN p, GEN p2inv)
805
{
806
GEN p1,x,x1,x2,y,y1,y2;
807
808
x1 = gel(z1,1); y1 = gel(z1,2);
809
x2 = gel(z2,1); y2 = gel(z2,2);
810
if (x1 == x2)
811
p1 = Fp_add(a4, mulii(x1,mului(3,x1)), p);
812
else
813
p1 = Fp_sub(y2,y1, p);
814
815
p1 = Fp_mul(p1, p2inv, p);
816
x = Fp_sub(sqri(p1), addii(x1,x2), p);
817
y = Fp_sub(mulii(p1,subii(x1,x)), y1, p);
818
affii(x, x1);
819
affii(y, y1);
820
}
821
822
/* make sure *x has lgefint >= k */
823
static void
824
_fix(GEN x, long k)
825
{
826
GEN y = (GEN)*x;
827
if (lgefint(y) < k) { GEN p1 = cgeti(k); affii(y,p1); *x = (long)p1; }
828
}
829
830
/* Return the lift of a (mod b), which is closest to c */
831
static GEN
832
closest_lift(GEN a, GEN b, GEN c)
833
{
834
return addii(a, mulii(b, diviiround(subii(c,a), b)));
835
}
836
837
static long
838
get_table_size(GEN pordmin, GEN B)
839
{
840
pari_sp av = avma;
841
GEN t = ceilr( sqrtr( divri(itor(pordmin, DEFAULTPREC), B) ) );
842
if (is_bigint(t))
843
pari_err_OVERFLOW("ellap [large prime: install the 'seadata' package]");
844
set_avma(av);
845
return itos(t) >> 1;
846
}
847
848
/* Find x such that kronecker(u = x^3+c4x+c6, p) is KRO.
849
* Return point [x*u,u^2] on E (KRO=1) / E^twist (KRO=-1) */
850
static GEN
851
Fp_ellpoint(long KRO, ulong *px, GEN c4, GEN c6, GEN p)
852
{
853
ulong x = *px;
854
GEN u;
855
for(;;)
856
{
857
x++; /* u = x^3 + c4 x + c6 */
858
u = modii(addii(c6, mului(x, addii(c4, sqru(x)))), p);
859
if (kronecker(u,p) == KRO) break;
860
}
861
*px = x;
862
return mkvec2(modii(mului(x,u),p), Fp_sqr(u,p));
863
}
864
static GEN
865
Fl_ellpoint(long KRO, ulong *px, ulong c4, ulong c6, ulong p)
866
{
867
ulong t, u, x = *px;
868
for(;;)
869
{
870
if (++x >= p) pari_err_PRIME("ellap",utoi(p));
871
t = Fl_add(c4, Fl_sqr(x,p), p);
872
u = Fl_add(c6, Fl_mul(x, t, p), p);
873
if (krouu(u,p) == KRO) break;
874
}
875
*px = x;
876
return mkvecsmall2(Fl_mul(x,u,p), Fl_sqr(u,p));
877
}
878
879
static GEN ap_j1728(GEN a4,GEN p);
880
/* compute a_p using Shanks/Mestre + Montgomery's trick. Assume p > 457 */
881
static GEN
882
Fp_ellcard_Shanks(GEN c4, GEN c6, GEN p)
883
{
884
pari_timer T;
885
long *tx, *ty, *ti, pfinal, i, j, s, KRO, nb;
886
ulong x;
887
pari_sp av = avma, av2;
888
GEN p1, P, mfh, h, F,f, fh,fg, pordmin, u, v, p1p, p2p, A, B, a4, pts;
889
tx = NULL;
890
ty = ti = NULL; /* gcc -Wall */
891
892
if (!signe(c6)) {
893
GEN ap = ap_j1728(c4, p);
894
return gerepileuptoint(av, subii(addiu(p,1), ap));
895
}
896
897
if (DEBUGLEVEL >= 6) timer_start(&T);
898
/* once #E(Fp) is know mod B >= pordmin, it is completely determined */
899
pordmin = addiu(sqrti(gmul2n(p,4)), 1); /* ceil( 4sqrt(p) ) */
900
p1p = addiu(p, 1);
901
p2p = shifti(p1p, 1);
902
x = 0; KRO = 0;
903
/* how many 2-torsion points ? */
904
switch(FpX_nbroots(mkpoln(4, gen_1, gen_0, c4, c6), p))
905
{
906
case 3: A = gen_0; B = utoipos(4); break;
907
case 1: A = gen_0; B = gen_2; break;
908
default: A = gen_1; B = gen_2; break; /* 0 */
909
}
910
for(;;)
911
{
912
h = closest_lift(A, B, p1p);
913
if (!KRO) /* first time, initialize */
914
{
915
KRO = kronecker(c6,p);
916
f = mkvec2(gen_0, Fp_sqr(c6,p));
917
}
918
else
919
{
920
KRO = -KRO;
921
f = Fp_ellpoint(KRO, &x, c4,c6,p);
922
}
923
/* [ux, u^2] is on E_u: y^2 = x^3 + c4 u^2 x + c6 u^3
924
* E_u isomorphic to E (resp. E') iff KRO = 1 (resp. -1)
925
* #E(F_p) = p+1 - a_p, #E'(F_p) = p+1 + a_p
926
*
927
* #E_u(Fp) = A (mod B), h is close to #E_u(Fp) */
928
a4 = modii(mulii(c4, gel(f,2)), p); /* c4 for E_u */
929
fh = FpE_mul(f, h, a4, p);
930
if (ell_is_inf(fh)) goto FOUND;
931
932
s = get_table_size(pordmin, B);
933
/* look for h s.t f^h = 0 */
934
if (!tx)
935
{ /* first time: initialize */
936
tx = newblock(3*(s+1));
937
ty = tx + (s+1);
938
ti = ty + (s+1);
939
}
940
F = FpE_mul(f,B,a4,p);
941
*tx = evaltyp(t_VECSMALL) | evallg(s+1);
942
943
/* F = B.f */
944
P = gcopy(fh);
945
if (s < 3)
946
{ /* we're nearly done: naive search */
947
GEN q1 = P, mF = FpE_neg(F, p); /* -F */
948
for (i=1;; i++)
949
{
950
P = FpE_add(P,F,a4,p); /* h.f + i.F */
951
if (ell_is_inf(P)) { h = addii(h, mului(i,B)); goto FOUND; }
952
q1 = FpE_add(q1,mF,a4,p); /* h.f - i.F */
953
if (ell_is_inf(q1)) { h = subii(h, mului(i,B)); goto FOUND; }
954
}
955
}
956
/* Baby Step/Giant Step */
957
nb = minss(128, s >> 1); /* > 0. Will do nb pts at a time: faster inverse */
958
pts = cgetg(nb+1, t_VEC);
959
j = lgefint(p);
960
for (i=1; i<=nb; i++)
961
{ /* baby steps */
962
gel(pts,i) = P; /* h.f + (i-1).F */
963
_fix(P+1, j); tx[i] = mod2BIL(gel(P,1));
964
_fix(P+2, j); ty[i] = mod2BIL(gel(P,2));
965
P = FpE_add(P,F,a4,p); /* h.f + i.F */
966
if (ell_is_inf(P)) { h = addii(h, mului(i,B)); goto FOUND; }
967
}
968
mfh = FpE_neg(fh, p);
969
fg = FpE_add(P,mfh,a4,p); /* h.f + nb.F - h.f = nb.F */
970
if (ell_is_inf(fg)) { h = mului(nb,B); goto FOUND; }
971
u = cgetg(nb+1, t_VEC);
972
av2 = avma; /* more baby steps, nb points at a time */
973
while (i <= s)
974
{
975
long maxj;
976
for (j=1; j<=nb; j++) /* adding nb.F (part 1) */
977
{
978
P = gel(pts,j); /* h.f + (i-nb-1+j-1).F */
979
gel(u,j) = subii(gel(fg,1), gel(P,1));
980
if (!signe(gel(u,j))) /* sum = 0 or doubling */
981
{
982
long k = i+j-2;
983
if (equalii(gel(P,2),gel(fg,2))) k -= 2*nb; /* fg == P */
984
h = addii(h, mulsi(k,B)); goto FOUND;
985
}
986
}
987
v = FpV_inv(u, p);
988
maxj = (i-1 + nb <= s)? nb: s % nb;
989
for (j=1; j<=maxj; j++,i++) /* adding nb.F (part 2) */
990
{
991
P = gel(pts,j);
992
FpE_add_ip(P,fg, a4,p, gel(v,j));
993
tx[i] = mod2BIL(gel(P,1));
994
ty[i] = mod2BIL(gel(P,2));
995
}
996
set_avma(av2);
997
}
998
P = FpE_add(gel(pts,j-1),mfh,a4,p); /* = (s-1).F */
999
if (ell_is_inf(P)) { h = mului(s-1,B); goto FOUND; }
1000
if (DEBUGLEVEL >= 6)
1001
timer_printf(&T, "[Fp_ellcard_Shanks] baby steps, s = %ld",s);
1002
1003
/* giant steps: fg = s.F */
1004
fg = FpE_add(P,F,a4,p);
1005
if (ell_is_inf(fg)) { h = mului(s,B); goto FOUND; }
1006
pfinal = mod2BIL(p); av2 = avma;
1007
/* Goal of the following: sort points by increasing x-coordinate hash.
1008
* Done in a complicated way to avoid allocating a large temp vector */
1009
p1 = vecsmall_indexsort(tx); /* = permutation sorting tx */
1010
for (i=1; i<=s; i++) ti[i] = tx[p1[i]];
1011
/* ti = tx sorted */
1012
for (i=1; i<=s; i++) { tx[i] = ti[i]; ti[i] = ty[p1[i]]; }
1013
/* tx is sorted. ti = ty sorted */
1014
for (i=1; i<=s; i++) { ty[i] = ti[i]; ti[i] = p1[i]; }
1015
/* ty is sorted. ti = permutation sorting tx */
1016
if (DEBUGLEVEL >= 6) timer_printf(&T, "[Fp_ellcard_Shanks] sorting");
1017
set_avma(av2);
1018
1019
gaffect(fg, gel(pts,1));
1020
for (j=2; j<=nb; j++) /* pts[j] = j.fg = (s*j).F */
1021
{
1022
P = FpE_add(gel(pts,j-1),fg,a4,p);
1023
if (ell_is_inf(P)) { h = mulii(mulss(s,j), B); goto FOUND; }
1024
gaffect(P, gel(pts,j));
1025
}
1026
/* replace fg by nb.fg since we do nb points at a time */
1027
set_avma(av2);
1028
fg = gcopy(gel(pts,nb)); /* copy: we modify (temporarily) pts[nb] below */
1029
av2 = avma;
1030
1031
for (i=1,j=1; ; i++)
1032
{
1033
GEN ftest = gel(pts,j);
1034
long m, l = 1, r = s+1;
1035
long k, k2, j2;
1036
1037
set_avma(av2);
1038
k = mod2BIL(gel(ftest,1));
1039
while (l < r)
1040
{
1041
m = (l+r) >> 1;
1042
if (tx[m] < k) l = m+1; else r = m;
1043
}
1044
if (r <= s && tx[r] == k)
1045
{
1046
while (r && tx[r] == k) r--;
1047
k2 = mod2BIL(gel(ftest,2));
1048
for (r++; r <= s && tx[r] == k; r++)
1049
if (ty[r] == k2 || ty[r] == pfinal - k2)
1050
{ /* [h+j2] f == +/- ftest (= [i.s] f)? */
1051
j2 = ti[r] - 1;
1052
if (DEBUGLEVEL >=6)
1053
timer_printf(&T, "[Fp_ellcard_Shanks] giant steps, i = %ld",i);
1054
P = FpE_add(FpE_mul(F,stoi(j2),a4,p),fh,a4,p);
1055
if (equalii(gel(P,1), gel(ftest,1)))
1056
{
1057
if (equalii(gel(P,2), gel(ftest,2))) i = -i;
1058
h = addii(h, mulii(addis(mulss(s,i), j2), B));
1059
goto FOUND;
1060
}
1061
}
1062
}
1063
if (++j > nb)
1064
{ /* compute next nb points */
1065
long save = 0; /* gcc -Wall */;
1066
for (j=1; j<=nb; j++)
1067
{
1068
P = gel(pts,j);
1069
gel(u,j) = subii(gel(fg,1), gel(P,1));
1070
if (gel(u,j) == gen_0) /* occurs once: i = j = nb, P == fg */
1071
{
1072
gel(u,j) = shifti(gel(P,2),1);
1073
save = fg[1]; fg[1] = P[1];
1074
}
1075
}
1076
v = FpV_inv(u, p);
1077
for (j=1; j<=nb; j++)
1078
FpE_add_ip(gel(pts,j),fg,a4,p, gel(v,j));
1079
if (i == nb) { fg[1] = save; }
1080
j = 1;
1081
}
1082
}
1083
FOUND: /* found a point of exponent h on E_u */
1084
h = FpE_order(f, h, a4, p);
1085
/* h | #E_u(Fp) = A (mod B) */
1086
A = Z_chinese_all(A, gen_0, B, h, &B);
1087
if (cmpii(B, pordmin) >= 0) break;
1088
/* not done: update A mod B for the _next_ curve, isomorphic to
1089
* the quadratic twist of this one */
1090
A = remii(subii(p2p,A), B); /* #E(Fp)+#E'(Fp) = 2p+2 */
1091
}
1092
if (tx) killblock(tx);
1093
h = closest_lift(A, B, p1p);
1094
return gerepileuptoint(av, KRO==1? h: subii(p2p,h));
1095
}
1096
1097
typedef struct
1098
{
1099
ulong x,y,i;
1100
} multiple;
1101
1102
static int
1103
compare_multiples(multiple *a, multiple *b) { return a->x > b->x? 1:a->x<b->x?-1:0; }
1104
1105
/* find x such that h := a + b x is closest to c and return h:
1106
* x = round((c-a) / b) = floor( (2(c-a) + b) / 2b )
1107
* Assume 0 <= a < b < c and b + 2c < 2^BIL */
1108
static ulong
1109
uclosest_lift(ulong a, ulong b, ulong c)
1110
{
1111
ulong x = (b + ((c-a) << 1)) / (b << 1);
1112
return a + b * x;
1113
}
1114
1115
static long
1116
Fle_dbl_inplace(GEN P, ulong a4, ulong p)
1117
{
1118
ulong x, y, slope;
1119
if (!P[2]) return 1;
1120
x = P[1]; y = P[2];
1121
slope = Fl_div(Fl_add(Fl_triple(Fl_sqr(x,p), p), a4, p),
1122
Fl_double(y, p), p);
1123
P[1] = Fl_sub(Fl_sqr(slope, p), Fl_double(x, p), p);
1124
P[2] = Fl_sub(Fl_mul(slope, Fl_sub(x, P[1], p), p), y, p);
1125
return 0;
1126
}
1127
1128
static long
1129
Fle_add_inplace(GEN P, GEN Q, ulong a4, ulong p)
1130
{
1131
ulong Px, Py, Qx, Qy, slope;
1132
if (ell_is_inf(Q)) return 0;
1133
Px = P[1]; Py = P[2];
1134
Qx = Q[1]; Qy = Q[2];
1135
if (Px==Qx)
1136
return Py==Qy ? Fle_dbl_inplace(P, a4, p): 1;
1137
slope = Fl_div(Fl_sub(Py, Qy, p), Fl_sub(Px, Qx, p), p);
1138
P[1] = Fl_sub(Fl_sub(Fl_sqr(slope, p), Px, p), Qx, p);
1139
P[2] = Fl_sub(Fl_mul(slope, Fl_sub(Px, P[1], p), p), Py, p);
1140
return 0;
1141
}
1142
1143
/* assume 99 < p < 2^(BIL-1) - 2^((BIL+1)/2) and e has good reduction at p.
1144
* Should use Barett reduction + multi-inverse. See Fp_ellcard_Shanks() */
1145
static long
1146
Fl_ellcard_Shanks(ulong c4, ulong c6, ulong p)
1147
{
1148
GEN f, fh, fg, ftest, F;
1149
ulong i, l, r, s, h, x, cp4, p1p, p2p, pordmin,A,B;
1150
long KRO;
1151
pari_sp av = avma;
1152
multiple *table;
1153
1154
if (!c6) {
1155
GEN ap = ap_j1728(utoi(c4), utoipos(p));
1156
return gc_long(av, p+1 - itos(ap));
1157
}
1158
1159
pordmin = (ulong)(1 + 4*sqrt((double)p));
1160
p1p = p+1;
1161
p2p = p1p << 1;
1162
x = 0; KRO = 0;
1163
switch(Flx_nbroots(mkvecsmall5(0L, c6,c4,0L,1L), p))
1164
{
1165
case 3: A = 0; B = 4; break;
1166
case 1: A = 0; B = 2; break;
1167
default: A = 1; B = 2; break; /* 0 */
1168
}
1169
for(;;)
1170
{ /* see comments in Fp_ellcard_Shanks */
1171
h = uclosest_lift(A, B, p1p);
1172
if (!KRO) /* first time, initialize */
1173
{
1174
KRO = krouu(c6,p); /* != 0 */
1175
f = mkvecsmall2(0, Fl_sqr(c6,p));
1176
}
1177
else
1178
{
1179
KRO = -KRO;
1180
f = Fl_ellpoint(KRO, &x, c4,c6,p);
1181
}
1182
cp4 = Fl_mul(c4, f[2], p);
1183
fh = Fle_mulu(f, h, cp4, p);
1184
if (ell_is_inf(fh)) goto FOUND;
1185
1186
s = (ulong) (sqrt(((double)pordmin)/B) / 2);
1187
if (!s) s = 1;
1188
table = (multiple *) stack_malloc((s+1) * sizeof(multiple));
1189
F = Fle_mulu(f, B, cp4, p);
1190
for (i=0; i < s; i++)
1191
{
1192
table[i].x = fh[1];
1193
table[i].y = fh[2];
1194
table[i].i = i;
1195
if (Fle_add_inplace(fh, F, cp4, p)) { h += B*(i+1); goto FOUND; }
1196
}
1197
qsort(table,s,sizeof(multiple),(QSCOMP)compare_multiples);
1198
fg = Fle_mulu(F, s, cp4, p); ftest = zv_copy(fg);
1199
if (ell_is_inf(ftest)) {
1200
if (!uisprime(p)) pari_err_PRIME("ellap",utoi(p));
1201
pari_err_BUG("ellap (f^(i*s) = 1)");
1202
}
1203
for (i=1; ; i++)
1204
{
1205
l=0; r=s;
1206
while (l<r)
1207
{
1208
ulong m = (l+r) >> 1;
1209
if (table[m].x < uel(ftest,1)) l=m+1; else r=m;
1210
}
1211
if (r < s && table[r].x == uel(ftest,1)) break;
1212
if (Fle_add_inplace(ftest, fg, cp4, p)) pari_err_PRIME("ellap",utoi(p));
1213
}
1214
h += table[r].i * B;
1215
if (table[r].y == uel(ftest,2))
1216
h -= s * i * B;
1217
else
1218
h += s * i * B;
1219
FOUND:
1220
h = itou(Fle_order(f, utoipos(h), cp4, p));
1221
/* h | #E_u(Fp) = A (mod B) */
1222
{
1223
GEN C;
1224
A = itou( Z_chinese_all(gen_0, utoi(A), utoipos(h), utoipos(B), &C) );
1225
if (abscmpiu(C, pordmin) >= 0) { /* uclosest_lift could overflow */
1226
h = itou( closest_lift(utoi(A), C, utoipos(p1p)) );
1227
break;
1228
}
1229
B = itou(C);
1230
}
1231
A = (p2p - A) % B; set_avma(av);
1232
}
1233
return gc_long(av, KRO==1? h: p2p-h);
1234
}
1235
1236
/** ellap from CM (original code contributed by Mark Watkins) **/
1237
1238
static GEN
1239
ap_j0(GEN a6,GEN p)
1240
{
1241
GEN a, b, e, d;
1242
if (umodiu(p,3) != 1) return gen_0;
1243
(void)cornacchia2(utoipos(27),p, &a,&b);
1244
if (umodiu(a, 3) == 1) a = negi(a);
1245
d = mulis(a6,-108);
1246
e = diviuexact(shifti(p,-1), 3); /* (p-1) / 6 */
1247
return centermod(mulii(a, Fp_pow(d, e, p)), p);
1248
}
1249
static GEN
1250
ap_j1728(GEN a4,GEN p)
1251
{
1252
GEN a, b, e;
1253
if (mod4(p) != 1) return gen_0;
1254
(void)cornacchia2(utoipos(4),p, &a,&b);
1255
if (Mod4(a)==0) a = b;
1256
if (Mod2(a)==1) a = shifti(a,1);
1257
if (Mod8(a)==6) a = negi(a);
1258
e = shifti(p,-2); /* (p-1) / 4 */
1259
return centermod(mulii(a, Fp_pow(a4, e, p)), p);
1260
}
1261
static GEN
1262
ap_j8000(GEN a6, GEN p)
1263
{
1264
GEN a, b;
1265
long r = mod8(p), s = 1;
1266
if (r != 1 && r != 3) return gen_0;
1267
(void)cornacchia2(utoipos(8),p, &a,&b);
1268
switch(Mod16(a)) {
1269
case 2: case 6: if (Mod4(b)) s = -s;
1270
break;
1271
case 10: case 14: if (!Mod4(b)) s = -s;
1272
break;
1273
}
1274
if (kronecker(mulis(a6, 42), p) < 0) s = -s;
1275
return s > 0? a: negi(a);
1276
}
1277
static GEN
1278
ap_j287496(GEN a6, GEN p)
1279
{
1280
GEN a, b;
1281
long s = 1;
1282
if (mod4(p) != 1) return gen_0;
1283
(void)cornacchia2(utoipos(4),p, &a,&b);
1284
if (Mod4(a)==0) a = b;
1285
if (Mod2(a)==1) a = shifti(a,1);
1286
if (Mod8(a)==6) s = -s;
1287
if (krosi(2,p) < 0) s = -s;
1288
if (kronecker(mulis(a6, -14), p) < 0) s = -s;
1289
return s > 0? a: negi(a);
1290
}
1291
static GEN
1292
ap_cm(int CM, long A6B, GEN a6, GEN p)
1293
{
1294
GEN a, b;
1295
long s = 1;
1296
if (krosi(CM,p) < 0) return gen_0;
1297
(void)cornacchia2(utoipos(-CM),p, &a, &b);
1298
if ((CM&3) == 0) CM >>= 2;
1299
if ((krois(a, -CM) > 0) ^ (CM == -7)) s = -s;
1300
if (kronecker(mulis(a6,A6B), p) < 0) s = -s;
1301
return s > 0? a: negi(a);
1302
}
1303
static GEN
1304
ec_ap_cm(int CM, GEN a4, GEN a6, GEN p)
1305
{
1306
switch(CM)
1307
{
1308
case -3: return ap_j0(a6, p);
1309
case -4: return ap_j1728(a4, p);
1310
case -8: return ap_j8000(a6, p);
1311
case -16: return ap_j287496(a6, p);
1312
case -7: return ap_cm(CM, -2, a6, p);
1313
case -11: return ap_cm(CM, 21, a6, p);
1314
case -12: return ap_cm(CM, 22, a6, p);
1315
case -19: return ap_cm(CM, 1, a6, p);
1316
case -27: return ap_cm(CM, 253, a6, p);
1317
case -28: return ap_cm(-7, -114, a6, p); /* yes, -7 ! */
1318
case -43: return ap_cm(CM, 21, a6, p);
1319
case -67: return ap_cm(CM, 217, a6, p);
1320
case -163:return ap_cm(CM, 185801, a6, p);
1321
default: return NULL;
1322
}
1323
}
1324
1325
static GEN
1326
Fp_ellj_nodiv(GEN a4, GEN a6, GEN p)
1327
{
1328
GEN a43 = Fp_mulu(Fp_powu(a4, 3, p), 4, p);
1329
GEN a62 = Fp_mulu(Fp_sqr(a6, p), 27, p);
1330
return mkvec2(Fp_mulu(a43, 1728, p), Fp_add(a43, a62, p));
1331
}
1332
1333
GEN
1334
Fp_ellj(GEN a4, GEN a6, GEN p)
1335
{
1336
pari_sp av = avma;
1337
GEN z;
1338
if (lgefint(p) == 3)
1339
{
1340
ulong pp = p[2];
1341
return utoi(Fl_ellj(umodiu(a4,pp), umodiu(a6,pp), pp));
1342
}
1343
z = Fp_ellj_nodiv(a4, a6, p);
1344
return gerepileuptoint(av,Fp_div(gel(z,1),gel(z,2),p));
1345
}
1346
1347
static GEN /* Only compute a mod p, so assume p>=17 */
1348
Fp_ellcard_CM(GEN a4, GEN a6, GEN p)
1349
{
1350
pari_sp av = avma;
1351
GEN a;
1352
if (!signe(a4)) a = ap_j0(a6,p);
1353
else if (!signe(a6)) a = ap_j1728(a4,p);
1354
else
1355
{
1356
GEN j = Fp_ellj_nodiv(a4, a6, p);
1357
long CM = Fp_ellj_get_CM(gel(j,1), gel(j,2), p);
1358
if (!CM) return gc_NULL(av);
1359
a = ec_ap_cm(CM,a4,a6,p);
1360
}
1361
return gerepileuptoint(av, subii(addiu(p,1),a));
1362
}
1363
1364
GEN
1365
Fp_ellcard(GEN a4, GEN a6, GEN p)
1366
{
1367
long lp = expi(p);
1368
ulong pp = p[2];
1369
if (lp < 11)
1370
return utoi(pp+1 - Fl_elltrace_naive(umodiu(a4,pp), umodiu(a6,pp), pp));
1371
{ GEN a = Fp_ellcard_CM(a4,a6,p); if (a) return a; }
1372
if (lp >= 56)
1373
return Fp_ellcard_SEA(a4, a6, p, 0);
1374
if (lp <= BITS_IN_LONG-2)
1375
return utoi(Fl_ellcard_Shanks(umodiu(a4,pp), umodiu(a6,pp), pp));
1376
return Fp_ellcard_Shanks(a4, a6, p);
1377
}
1378
1379
long
1380
Fl_elltrace(ulong a4, ulong a6, ulong p)
1381
{
1382
pari_sp av;
1383
long lp;
1384
GEN a;
1385
if (p < (1<<11)) return Fl_elltrace_naive(a4, a6, p);
1386
lp = expu(p);
1387
if (lp <= minss(56, BITS_IN_LONG-2)) return p+1-Fl_ellcard_Shanks(a4, a6, p);
1388
av = avma; a = subui(p+1, Fp_ellcard(utoi(a4), utoi(a6), utoipos(p)));
1389
return gc_long(av, itos(a));
1390
}
1391
long
1392
Fl_elltrace_CM(long CM, ulong a4, ulong a6, ulong p)
1393
{
1394
pari_sp av;
1395
GEN a;
1396
if (!CM) return Fl_elltrace(a4,a6,p);
1397
if (p < (1<<11)) return Fl_elltrace_naive(a4, a6, p);
1398
av = avma; a = ec_ap_cm(CM, utoi(a4), utoi(a6), utoipos(p));
1399
return gc_long(av, itos(a));
1400
}
1401
1402
static GEN
1403
_FpE_pairorder(void *E, GEN P, GEN Q, GEN m, GEN F)
1404
{
1405
struct _FpE *e = (struct _FpE *) E;
1406
return Fp_order(FpE_weilpairing(P,Q,m,e->a4,e->p), F, e->p);
1407
}
1408
1409
GEN
1410
Fp_ellgroup(GEN a4, GEN a6, GEN N, GEN p, GEN *pt_m)
1411
{
1412
struct _FpE e;
1413
e.a4=a4; e.a6=a6; e.p=p;
1414
return gen_ellgroup(N, subiu(p,1), pt_m, (void*)&e, &FpE_group, _FpE_pairorder);
1415
}
1416
1417
GEN
1418
Fp_ellgens(GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN p)
1419
{
1420
GEN P;
1421
pari_sp av = avma;
1422
struct _FpE e;
1423
e.a4=a4; e.a6=a6; e.p=p;
1424
switch(lg(D)-1)
1425
{
1426
case 1:
1427
P = gen_gener(gel(D,1), (void*)&e, &FpE_group);
1428
P = mkvec(FpE_changepoint(P, ch, p));
1429
break;
1430
default:
1431
P = gen_ellgens(gel(D,1), gel(D,2), m, (void*)&e, &FpE_group, _FpE_pairorder);
1432
gel(P,1) = FpE_changepoint(gel(P,1), ch, p);
1433
gel(P,2) = FpE_changepoint(gel(P,2), ch, p);
1434
break;
1435
}
1436
return gerepilecopy(av, P);
1437
}
1438
1439
/* Not so fast arithmetic with points over elliptic curves over FpXQ */
1440
1441
/***********************************************************************/
1442
/** **/
1443
/** FpXQE **/
1444
/** **/
1445
/***********************************************************************/
1446
1447
/* Theses functions deal with point over elliptic curves over FpXQ defined
1448
* by an equation of the form y^2=x^3+a4*x+a6.
1449
* Most of the time a6 is omitted since it can be recovered from any point
1450
* on the curve.
1451
*/
1452
1453
GEN
1454
RgE_to_FpXQE(GEN x, GEN T, GEN p)
1455
{
1456
if (ell_is_inf(x)) return x;
1457
retmkvec2(Rg_to_FpXQ(gel(x,1),T,p),Rg_to_FpXQ(gel(x,2),T,p));
1458
}
1459
1460
GEN
1461
FpXQE_changepoint(GEN x, GEN ch, GEN T, GEN p)
1462
{
1463
pari_sp av = avma;
1464
GEN p1,z,u,r,s,t,v,v2,v3;
1465
if (ell_is_inf(x)) return x;
1466
u = gel(ch,1); r = gel(ch,2);
1467
s = gel(ch,3); t = gel(ch,4);
1468
v = FpXQ_inv(u, T, p); v2 = FpXQ_sqr(v, T, p); v3 = FpXQ_mul(v,v2, T, p);
1469
p1 = FpX_sub(gel(x,1),r, p);
1470
z = cgetg(3,t_VEC);
1471
gel(z,1) = FpXQ_mul(v2, p1, T, p);
1472
gel(z,2) = FpXQ_mul(v3, FpX_sub(gel(x,2), FpX_add(FpXQ_mul(s,p1, T, p),t, p), p), T, p);
1473
return gerepileupto(av, z);
1474
}
1475
1476
GEN
1477
FpXQE_changepointinv(GEN x, GEN ch, GEN T, GEN p)
1478
{
1479
GEN u, r, s, t, X, Y, u2, u3, u2X, z;
1480
if (ell_is_inf(x)) return x;
1481
X = gel(x,1); Y = gel(x,2);
1482
u = gel(ch,1); r = gel(ch,2);
1483
s = gel(ch,3); t = gel(ch,4);
1484
u2 = FpXQ_sqr(u, T, p); u3 = FpXQ_mul(u,u2, T, p);
1485
u2X = FpXQ_mul(u2,X, T, p);
1486
z = cgetg(3, t_VEC);
1487
gel(z,1) = FpX_add(u2X,r, p);
1488
gel(z,2) = FpX_add(FpXQ_mul(u3,Y, T, p), FpX_add(FpXQ_mul(s,u2X, T, p), t, p), p);
1489
return z;
1490
}
1491
1492
static GEN
1493
nonsquare_FpXQ(GEN T, GEN p)
1494
{
1495
pari_sp av = avma;
1496
long n = degpol(T), v = varn(T);
1497
GEN a;
1498
if (odd(n))
1499
{
1500
GEN z = cgetg(3, t_POL);
1501
z[1] = evalsigne(1) | evalvarn(v);
1502
gel(z,2) = nonsquare_Fp(p); return z;
1503
}
1504
do
1505
{
1506
set_avma(av);
1507
a = random_FpX(n, v, p);
1508
} while (FpXQ_issquare(a, T, p));
1509
return a;
1510
}
1511
1512
void
1513
FpXQ_elltwist(GEN a4, GEN a6, GEN T, GEN p, GEN *pt_a4, GEN *pt_a6)
1514
{
1515
GEN d = nonsquare_FpXQ(T, p);
1516
GEN d2 = FpXQ_sqr(d, T, p), d3 = FpXQ_mul(d2, d, T, p);
1517
*pt_a4 = FpXQ_mul(a4, d2, T, p);
1518
*pt_a6 = FpXQ_mul(a6, d3, T, p);
1519
}
1520
1521
static GEN
1522
FpXQE_dbl_slope(GEN P, GEN a4, GEN T, GEN p, GEN *slope)
1523
{
1524
GEN x, y, Q;
1525
if (ell_is_inf(P) || !signe(gel(P,2))) return ellinf();
1526
x = gel(P,1); y = gel(P,2);
1527
*slope = FpXQ_div(FpX_add(FpX_mulu(FpXQ_sqr(x, T, p), 3, p), a4, p),
1528
FpX_mulu(y, 2, p), T, p);
1529
Q = cgetg(3,t_VEC);
1530
gel(Q, 1) = FpX_sub(FpXQ_sqr(*slope, T, p), FpX_mulu(x, 2, p), p);
1531
gel(Q, 2) = FpX_sub(FpXQ_mul(*slope, FpX_sub(x, gel(Q, 1), p), T, p), y, p);
1532
return Q;
1533
}
1534
1535
GEN
1536
FpXQE_dbl(GEN P, GEN a4, GEN T, GEN p)
1537
{
1538
pari_sp av = avma;
1539
GEN slope;
1540
return gerepileupto(av, FpXQE_dbl_slope(P,a4,T,p,&slope));
1541
}
1542
1543
static GEN
1544
FpXQE_add_slope(GEN P, GEN Q, GEN a4, GEN T, GEN p, GEN *slope)
1545
{
1546
GEN Px, Py, Qx, Qy, R;
1547
if (ell_is_inf(P)) return Q;
1548
if (ell_is_inf(Q)) return P;
1549
Px = gel(P,1); Py = gel(P,2);
1550
Qx = gel(Q,1); Qy = gel(Q,2);
1551
if (ZX_equal(Px, Qx))
1552
{
1553
if (ZX_equal(Py, Qy))
1554
return FpXQE_dbl_slope(P, a4, T, p, slope);
1555
else
1556
return ellinf();
1557
}
1558
*slope = FpXQ_div(FpX_sub(Py, Qy, p), FpX_sub(Px, Qx, p), T, p);
1559
R = cgetg(3,t_VEC);
1560
gel(R, 1) = FpX_sub(FpX_sub(FpXQ_sqr(*slope, T, p), Px, p), Qx, p);
1561
gel(R, 2) = FpX_sub(FpXQ_mul(*slope, FpX_sub(Px, gel(R, 1), p), T, p), Py, p);
1562
return R;
1563
}
1564
1565
GEN
1566
FpXQE_add(GEN P, GEN Q, GEN a4, GEN T, GEN p)
1567
{
1568
pari_sp av = avma;
1569
GEN slope;
1570
return gerepileupto(av, FpXQE_add_slope(P,Q,a4,T,p,&slope));
1571
}
1572
1573
static GEN
1574
FpXQE_neg_i(GEN P, GEN p)
1575
{
1576
if (ell_is_inf(P)) return P;
1577
return mkvec2(gel(P,1), FpX_neg(gel(P,2), p));
1578
}
1579
1580
GEN
1581
FpXQE_neg(GEN P, GEN T, GEN p)
1582
{
1583
(void) T;
1584
if (ell_is_inf(P)) return ellinf();
1585
return mkvec2(gcopy(gel(P,1)), FpX_neg(gel(P,2), p));
1586
}
1587
1588
GEN
1589
FpXQE_sub(GEN P, GEN Q, GEN a4, GEN T, GEN p)
1590
{
1591
pari_sp av = avma;
1592
GEN slope;
1593
return gerepileupto(av, FpXQE_add_slope(P, FpXQE_neg_i(Q, p), a4, T, p, &slope));
1594
}
1595
1596
struct _FpXQE { GEN a4,a6,T,p; };
1597
static GEN
1598
_FpXQE_dbl(void *E, GEN P)
1599
{
1600
struct _FpXQE *ell = (struct _FpXQE *) E;
1601
return FpXQE_dbl(P, ell->a4, ell->T, ell->p);
1602
}
1603
static GEN
1604
_FpXQE_add(void *E, GEN P, GEN Q)
1605
{
1606
struct _FpXQE *ell=(struct _FpXQE *) E;
1607
return FpXQE_add(P, Q, ell->a4, ell->T, ell->p);
1608
}
1609
static GEN
1610
_FpXQE_mul(void *E, GEN P, GEN n)
1611
{
1612
pari_sp av = avma;
1613
struct _FpXQE *e=(struct _FpXQE *) E;
1614
long s = signe(n);
1615
if (!s || ell_is_inf(P)) return ellinf();
1616
if (s<0) P = FpXQE_neg(P, e->T, e->p);
1617
if (is_pm1(n)) return s>0? gcopy(P): P;
1618
return gerepilecopy(av, gen_pow_i(P, n, e, &_FpXQE_dbl, &_FpXQE_add));
1619
}
1620
1621
GEN
1622
FpXQE_mul(GEN P, GEN n, GEN a4, GEN T, GEN p)
1623
{
1624
struct _FpXQE E;
1625
E.a4= a4; E.T = T; E.p = p;
1626
return _FpXQE_mul(&E, P, n);
1627
}
1628
1629
/* Finds a random nonsingular point on E */
1630
1631
GEN
1632
random_FpXQE(GEN a4, GEN a6, GEN T, GEN p)
1633
{
1634
pari_sp ltop = avma;
1635
GEN x, x2, y, rhs;
1636
long v = get_FpX_var(T), d = get_FpX_degree(T);
1637
do
1638
{
1639
set_avma(ltop);
1640
x = random_FpX(d,v,p); /* x^3+a4*x+a6 = x*(x^2+a4)+a6 */
1641
x2 = FpXQ_sqr(x, T, p);
1642
rhs = FpX_add(FpXQ_mul(x, FpX_add(x2, a4, p), T, p), a6, p);
1643
} while ((!signe(rhs) && !signe(FpX_add(FpX_mulu(x2,3,p), a4, p)))
1644
|| !FpXQ_issquare(rhs, T, p));
1645
y = FpXQ_sqrt(rhs, T, p);
1646
if (!y) pari_err_PRIME("random_FpE", p);
1647
return gerepilecopy(ltop, mkvec2(x, y));
1648
}
1649
1650
static GEN
1651
_FpXQE_rand(void *E)
1652
{
1653
struct _FpXQE *e=(struct _FpXQE *) E;
1654
return random_FpXQE(e->a4, e->a6, e->T, e->p);
1655
}
1656
1657
static const struct bb_group FpXQE_group={_FpXQE_add,_FpXQE_mul,_FpXQE_rand,hash_GEN,ZXV_equal,ell_is_inf};
1658
1659
const struct bb_group *
1660
get_FpXQE_group(void ** pt_E, GEN a4, GEN a6, GEN T, GEN p)
1661
{
1662
struct _FpXQE *e = (struct _FpXQE *) stack_malloc(sizeof(struct _FpXQE));
1663
e->a4 = a4; e->a6 = a6; e->T = T; e->p = p;
1664
*pt_E = (void *) e;
1665
return &FpXQE_group;
1666
}
1667
1668
GEN
1669
FpXQE_order(GEN z, GEN o, GEN a4, GEN T, GEN p)
1670
{
1671
pari_sp av = avma;
1672
struct _FpXQE e;
1673
e.a4=a4; e.T=T; e.p=p;
1674
return gerepileuptoint(av, gen_order(z, o, (void*)&e, &FpXQE_group));
1675
}
1676
1677
GEN
1678
FpXQE_log(GEN a, GEN b, GEN o, GEN a4, GEN T, GEN p)
1679
{
1680
pari_sp av = avma;
1681
struct _FpXQE e;
1682
e.a4=a4; e.T=T; e.p=p;
1683
return gerepileuptoint(av, gen_PH_log(a, b, o, (void*)&e, &FpXQE_group));
1684
}
1685
1686
/***********************************************************************/
1687
/** **/
1688
/** Pairings **/
1689
/** **/
1690
/***********************************************************************/
1691
1692
/* Derived from APIP from and by Jerome Milan, 2012 */
1693
1694
static GEN
1695
FpXQE_vert(GEN P, GEN Q, GEN a4, GEN T, GEN p)
1696
{
1697
long vT = get_FpX_var(T);
1698
if (ell_is_inf(P))
1699
return pol_1(get_FpX_var(T));
1700
if (!ZX_equal(gel(Q, 1), gel(P, 1)))
1701
return FpX_sub(gel(Q, 1), gel(P, 1), p);
1702
if (signe(gel(P,2))!=0) return pol_1(vT);
1703
return FpXQ_inv(FpX_add(FpX_mulu(FpXQ_sqr(gel(P,1), T, p), 3, p),
1704
a4, p), T, p);
1705
}
1706
1707
static GEN
1708
FpXQE_Miller_line(GEN R, GEN Q, GEN slope, GEN a4, GEN T, GEN p)
1709
{
1710
long vT = get_FpX_var(T);
1711
GEN x = gel(Q, 1), y = gel(Q, 2);
1712
GEN tmp1 = FpX_sub(x, gel(R, 1), p);
1713
GEN tmp2 = FpX_add(FpXQ_mul(tmp1, slope, T, p), gel(R, 2), p);
1714
if (!ZX_equal(y, tmp2))
1715
return FpX_sub(y, tmp2, p);
1716
if (signe(y) == 0)
1717
return pol_1(vT);
1718
else
1719
{
1720
GEN s1, s2;
1721
GEN y2i = FpXQ_inv(FpX_mulu(y, 2, p), T, p);
1722
s1 = FpXQ_mul(FpX_add(FpX_mulu(FpXQ_sqr(x, T, p), 3, p), a4, p), y2i, T, p);
1723
if (!ZX_equal(s1, slope))
1724
return FpX_sub(s1, slope, p);
1725
s2 = FpXQ_mul(FpX_sub(FpX_mulu(x, 3, p), FpXQ_sqr(s1, T, p), p), y2i, T, p);
1726
return signe(s2)!=0 ? s2: y2i;
1727
}
1728
}
1729
1730
/* Computes the equation of the line tangent to R and returns its
1731
evaluation at the point Q. Also doubles the point R.
1732
*/
1733
1734
static GEN
1735
FpXQE_tangent_update(GEN R, GEN Q, GEN a4, GEN T, GEN p, GEN *pt_R)
1736
{
1737
if (ell_is_inf(R))
1738
{
1739
*pt_R = ellinf();
1740
return pol_1(get_FpX_var(T));
1741
}
1742
else if (!signe(gel(R,2)))
1743
{
1744
*pt_R = ellinf();
1745
return FpXQE_vert(R, Q, a4, T, p);
1746
} else {
1747
GEN slope;
1748
*pt_R = FpXQE_dbl_slope(R, a4, T, p, &slope);
1749
return FpXQE_Miller_line(R, Q, slope, a4, T, p);
1750
}
1751
}
1752
1753
/* Computes the equation of the line through R and P, and returns its
1754
evaluation at the point Q. Also adds P to the point R.
1755
*/
1756
1757
static GEN
1758
FpXQE_chord_update(GEN R, GEN P, GEN Q, GEN a4, GEN T, GEN p, GEN *pt_R)
1759
{
1760
if (ell_is_inf(R))
1761
{
1762
*pt_R = gcopy(P);
1763
return FpXQE_vert(P, Q, a4, T, p);
1764
}
1765
else if (ell_is_inf(P))
1766
{
1767
*pt_R = gcopy(R);
1768
return FpXQE_vert(R, Q, a4, T, p);
1769
}
1770
else if (ZX_equal(gel(P, 1), gel(R, 1)))
1771
{
1772
if (ZX_equal(gel(P, 2), gel(R, 2)))
1773
return FpXQE_tangent_update(R, Q, a4, T, p, pt_R);
1774
else
1775
{
1776
*pt_R = ellinf();
1777
return FpXQE_vert(R, Q, a4, T, p);
1778
}
1779
} else {
1780
GEN slope;
1781
*pt_R = FpXQE_add_slope(P, R, a4, T, p, &slope);
1782
return FpXQE_Miller_line(R, Q, slope, a4, T, p);
1783
}
1784
}
1785
1786
struct _FpXQE_miller { GEN p, T, a4, P; };
1787
static GEN
1788
FpXQE_Miller_dbl(void* E, GEN d)
1789
{
1790
struct _FpXQE_miller *m = (struct _FpXQE_miller *)E;
1791
GEN p = m->p;
1792
GEN T = m->T, a4 = m->a4, P = m->P;
1793
GEN v, line;
1794
GEN N = FpXQ_sqr(gel(d,1), T, p);
1795
GEN D = FpXQ_sqr(gel(d,2), T, p);
1796
GEN point = gel(d,3);
1797
line = FpXQE_tangent_update(point, P, a4, T, p, &point);
1798
N = FpXQ_mul(N, line, T, p);
1799
v = FpXQE_vert(point, P, a4, T, p);
1800
D = FpXQ_mul(D, v, T, p); return mkvec3(N, D, point);
1801
}
1802
1803
static GEN
1804
FpXQE_Miller_add(void* E, GEN va, GEN vb)
1805
{
1806
struct _FpXQE_miller *m = (struct _FpXQE_miller *)E;
1807
GEN p = m->p;
1808
GEN T = m->T, a4 = m->a4, P = m->P;
1809
GEN v, line, point;
1810
GEN na = gel(va,1), da = gel(va,2), pa = gel(va,3);
1811
GEN nb = gel(vb,1), db = gel(vb,2), pb = gel(vb,3);
1812
GEN N = FpXQ_mul(na, nb, T, p);
1813
GEN D = FpXQ_mul(da, db, T, p);
1814
line = FpXQE_chord_update(pa, pb, P, a4, T, p, &point);
1815
N = FpXQ_mul(N, line, T, p);
1816
v = FpXQE_vert(point, P, a4, T, p);
1817
D = FpXQ_mul(D, v, T, p); return mkvec3(N, D, point);
1818
}
1819
1820
/* Returns the Miller function f_{m, Q} evaluated at the point P using
1821
* the standard Miller algorithm. */
1822
static GEN
1823
FpXQE_Miller(GEN Q, GEN P, GEN m, GEN a4, GEN T, GEN p)
1824
{
1825
pari_sp av = avma;
1826
struct _FpXQE_miller d;
1827
GEN v, N, D, g1;
1828
1829
d.a4 = a4; d.T = T; d.p = p; d.P = P;
1830
g1 = pol_1(get_FpX_var(T));
1831
v = gen_pow_i(mkvec3(g1,g1,Q), m, (void*)&d,
1832
FpXQE_Miller_dbl, FpXQE_Miller_add);
1833
N = gel(v,1); D = gel(v,2);
1834
return gerepileupto(av, FpXQ_div(N, D, T, p));
1835
}
1836
1837
GEN
1838
FpXQE_weilpairing(GEN P, GEN Q, GEN m, GEN a4, GEN T, GEN p)
1839
{
1840
pari_sp av = avma;
1841
GEN N, D, w;
1842
if (ell_is_inf(P) || ell_is_inf(Q) || ZXV_equal(P,Q))
1843
return pol_1(get_FpX_var(T));
1844
N = FpXQE_Miller(P, Q, m, a4, T, p);
1845
D = FpXQE_Miller(Q, P, m, a4, T, p);
1846
w = FpXQ_div(N, D, T, p);
1847
if (mpodd(m)) w = FpX_neg(w, p);
1848
return gerepileupto(av, w);
1849
}
1850
1851
GEN
1852
FpXQE_tatepairing(GEN P, GEN Q, GEN m, GEN a4, GEN T, GEN p)
1853
{
1854
if (ell_is_inf(P) || ell_is_inf(Q)) return pol_1(get_FpX_var(T));
1855
return FpXQE_Miller(P, Q, m, a4, T, p);
1856
}
1857
1858
/***********************************************************************/
1859
/** **/
1860
/** issupersingular **/
1861
/** **/
1862
/***********************************************************************/
1863
1864
GEN
1865
FpXQ_ellj(GEN a4, GEN a6, GEN T, GEN p)
1866
{
1867
if (absequaliu(p,3)) return pol_0(get_FpX_var(T));
1868
else
1869
{
1870
pari_sp av=avma;
1871
GEN a43 = FpXQ_mul(a4,FpXQ_sqr(a4,T,p),T,p);
1872
GEN a62 = FpXQ_sqr(a6,T,p);
1873
GEN num = FpX_mulu(a43,6912,p);
1874
GEN den = FpX_add(FpX_mulu(a43,4,p),FpX_mulu(a62,27,p),p);
1875
return gerepileuptoleaf(av, FpXQ_div(num, den, T, p));
1876
}
1877
}
1878
1879
int
1880
FpXQ_elljissupersingular(GEN j, GEN T, GEN p)
1881
{
1882
pari_sp ltop = avma;
1883
1884
/* All supersingular j-invariants are in FF_{p^2}, so we first check
1885
* whether j is in FF_{p^2}. If d is odd, then FF_{p^2} is not a
1886
* subfield of FF_{p^d} so the j-invariants are all in FF_p. Hence
1887
* the j-invariants are in FF_{p^{2 - e}}. */
1888
ulong d = get_FpX_degree(T);
1889
GEN S;
1890
1891
if (degpol(j) <= 0) return Fp_elljissupersingular(constant_coeff(j), p);
1892
if (abscmpiu(p, 5) <= 0) return 0; /* j != 0*/
1893
1894
/* Set S so that FF_p[T]/(S) is isomorphic to FF_{p^2}: */
1895
if (d == 2)
1896
S = T;
1897
else { /* d > 2 */
1898
/* We construct FF_{p^2} = FF_p[t]/((T - j)(T - j^p)) which
1899
* injects into FF_{p^d} via the map T |--> j. */
1900
GEN j_pow_p = FpXQ_pow(j, p, T, p);
1901
GEN j_sum = FpX_add(j, j_pow_p, p), j_prod;
1902
long var = varn(T);
1903
if (degpol(j_sum) > 0) return gc_bool(ltop,0); /* j not in Fp^2 */
1904
j_prod = FpXQ_mul(j, j_pow_p, T, p);
1905
if (degpol(j_prod) > 0 ) return gc_bool(ltop,0); /* j not in Fp^2 */
1906
j_sum = constant_coeff(j_sum); j_prod = constant_coeff(j_prod);
1907
S = mkpoln(3, gen_1, Fp_neg(j_sum, p), j_prod);
1908
setvarn(S, var);
1909
j = pol_x(var);
1910
}
1911
return gc_bool(ltop, jissupersingular(j,S,p));
1912
}
1913
1914
/***********************************************************************/
1915
/** **/
1916
/** Point counting **/
1917
/** **/
1918
/***********************************************************************/
1919
1920
GEN
1921
elltrace_extension(GEN t, long n, GEN q)
1922
{
1923
pari_sp av = avma;
1924
GEN v = RgX_to_RgC(RgXQ_powu(pol_x(0), n, mkpoln(3,gen_1,negi(t),q)),2);
1925
GEN te = addii(shifti(gel(v,1),1), mulii(t,gel(v,2)));
1926
return gerepileuptoint(av, te);
1927
}
1928
1929
GEN
1930
Fp_ffellcard(GEN a4, GEN a6, GEN q, long n, GEN p)
1931
{
1932
pari_sp av = avma;
1933
GEN ap = subii(addiu(p, 1), Fp_ellcard(a4, a6, p));
1934
GEN te = elltrace_extension(ap, n, p);
1935
return gerepileuptoint(av, subii(addiu(q, 1), te));
1936
}
1937
1938
static GEN
1939
FpXQ_ellcardj(GEN a4, GEN a6, GEN j, GEN T, GEN q, GEN p, long n)
1940
{
1941
GEN q1 = addiu(q,1);
1942
if (signe(j)==0)
1943
{
1944
GEN W, w, t, N;
1945
if (umodiu(q,6)!=1) return q1;
1946
N = Fp_ffellcard(gen_0,gen_1,q,n,p);
1947
t = subii(q1, N);
1948
W = FpXQ_pow(a6,diviuexact(shifti(q,-1), 3),T,p);
1949
if (degpol(W)>0) /*p=5 mod 6*/
1950
return ZX_equal1(FpXQ_powu(W,3,T,p)) ? addii(q1,shifti(t,-1)):
1951
subii(q1,shifti(t,-1));
1952
w = modii(gel(W,2),p);
1953
if (equali1(w)) return N;
1954
if (equalii(w,subiu(p,1))) return addii(q1,t);
1955
else /*p=1 mod 6*/
1956
{
1957
GEN u = shifti(t,-1), v = sqrtint(diviuexact(subii(q,sqri(u)),3));
1958
GEN a = addii(u,v), b = shifti(v,1);
1959
if (equali1(Fp_powu(w,3,p)))
1960
{
1961
if (dvdii(addmulii(a, w, b), p))
1962
return subii(q1,subii(shifti(b,1),a));
1963
else
1964
return addii(q1,addii(a,b));
1965
}
1966
else
1967
{
1968
if (dvdii(submulii(a, w, b), p))
1969
return subii(q1,subii(a,shifti(b,1)));
1970
else
1971
return subii(q1,addii(a,b));
1972
}
1973
}
1974
} else if (equalii(j,modsi(1728,p)))
1975
{
1976
GEN w, W, N, t;
1977
if (mod4(q)==3) return q1;
1978
W = FpXQ_pow(a4,shifti(q,-2),T,p);
1979
if (degpol(W)>0) return q1; /*p=3 mod 4*/
1980
w = modii(gel(W,2),p);
1981
N = Fp_ffellcard(gen_1,gen_0,q,n,p);
1982
if (equali1(w)) return N;
1983
t = subii(q1, N);
1984
if (equalii(w,subiu(p,1))) return addii(q1,t);
1985
else /*p=1 mod 4*/
1986
{
1987
GEN u = shifti(t,-1), v = sqrtint(subii(q,sqri(u)));
1988
if (dvdii(addmulii(u, w, v), p))
1989
return subii(q1,shifti(v,1));
1990
else
1991
return addii(q1,shifti(v,1));
1992
}
1993
} else
1994
{
1995
GEN g = Fp_div(j, Fp_sub(utoi(1728), j, p), p);
1996
GEN l = FpXQ_div(FpX_mulu(a6,3,p),FpX_mulu(a4,2,p),T,p);
1997
GEN N = Fp_ffellcard(Fp_mulu(g,3,p),Fp_mulu(g,2,p),q,n,p);
1998
if (FpXQ_issquare(l,T,p)) return N;
1999
return subii(shifti(q1,1),N);
2000
}
2001
}
2002
2003
GEN
2004
FpXQ_ellcard(GEN a4, GEN a6, GEN T, GEN p)
2005
{
2006
pari_sp av = avma;
2007
long n = get_FpX_degree(T);
2008
GEN q = powiu(p, n), r, J;
2009
if (degpol(a4)<=0 && degpol(a6)<=0)
2010
r = Fp_ffellcard(constant_coeff(a4),constant_coeff(a6),q,n,p);
2011
else if (lgefint(p)==3)
2012
{
2013
ulong pp = p[2];
2014
r = Flxq_ellcard(ZX_to_Flx(a4,pp),ZX_to_Flx(a6,pp),ZX_to_Flx(T,pp),pp);
2015
}
2016
else if (degpol(J=FpXQ_ellj(a4,a6,T,p))<=0)
2017
r = FpXQ_ellcardj(a4,a6,constant_coeff(J),T,q,p,n);
2018
else
2019
r = Fq_ellcard_SEA(a4, a6, q, T, p, 0);
2020
return gerepileuptoint(av, r);
2021
}
2022
2023
static GEN
2024
_FpXQE_pairorder(void *E, GEN P, GEN Q, GEN m, GEN F)
2025
{
2026
struct _FpXQE *e = (struct _FpXQE *) E;
2027
return FpXQ_order(FpXQE_weilpairing(P,Q,m,e->a4,e->T,e->p), F, e->T, e->p);
2028
}
2029
2030
GEN
2031
FpXQ_ellgroup(GEN a4, GEN a6, GEN N, GEN T, GEN p, GEN *pt_m)
2032
{
2033
struct _FpXQE e;
2034
GEN q = powiu(p, get_FpX_degree(T));
2035
e.a4=a4; e.a6=a6; e.T=T; e.p=p;
2036
return gen_ellgroup(N, subiu(q,1), pt_m, (void*)&e, &FpXQE_group, _FpXQE_pairorder);
2037
}
2038
2039
GEN
2040
FpXQ_ellgens(GEN a4, GEN a6, GEN ch, GEN D, GEN m, GEN T, GEN p)
2041
{
2042
GEN P;
2043
pari_sp av = avma;
2044
struct _FpXQE e;
2045
e.a4=a4; e.a6=a6; e.T=T; e.p=p;
2046
switch(lg(D)-1)
2047
{
2048
case 1:
2049
P = gen_gener(gel(D,1), (void*)&e, &FpXQE_group);
2050
P = mkvec(FpXQE_changepoint(P, ch, T, p));
2051
break;
2052
default:
2053
P = gen_ellgens(gel(D,1), gel(D,2), m, (void*)&e, &FpXQE_group, _FpXQE_pairorder);
2054
gel(P,1) = FpXQE_changepoint(gel(P,1), ch, T, p);
2055
gel(P,2) = FpXQE_changepoint(gel(P,2), ch, T, p);
2056
break;
2057
}
2058
return gerepilecopy(av, P);
2059
}
2060
2061