Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

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

28485 views
License: GPL3
ubuntu2004
1
/* Copyright (C) 2014 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
/* Not so fast arithmetic with points over elliptic curves over Fl */
19
20
/***********************************************************************/
21
/** **/
22
/** Flj **/
23
/** **/
24
/***********************************************************************/
25
26
/* Arithmetic is implemented using Jacobian coordinates, representing
27
* a projective point (x : y : z) on E by [z*x , z^2*y , z]. This is
28
* probably not the fastest representation available for the given
29
* problem, but they're easy to implement and up to 60% faster than
30
* the school-book method. */
31
32
/* Cost: 1M + 8S + 1*a + 10add + 1*8 + 2*2 + 1*3.
33
* http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl */
34
INLINE void
35
Flj_dbl_indir_pre(GEN P, GEN Q, ulong a4, ulong p, ulong pi)
36
{
37
ulong X1, Y1, Z1;
38
ulong XX, YY, YYYY, ZZ, S, M, T;
39
40
X1 = P[1]; Y1 = P[2]; Z1 = P[3];
41
42
if (Z1 == 0) { Q[1] = X1; Q[2] = Y1; Q[3] = Z1; return; }
43
44
XX = Fl_sqr_pre(X1, p, pi);
45
YY = Fl_sqr_pre(Y1, p, pi);
46
YYYY = Fl_sqr_pre(YY, p, pi);
47
ZZ = Fl_sqr_pre(Z1, p, pi);
48
S = Fl_double(Fl_sub(Fl_sqr_pre(Fl_add(X1, YY, p), p, pi),
49
Fl_add(XX, YYYY, p), p), p);
50
M = Fl_addmul_pre(Fl_triple(XX, p), a4, Fl_sqr_pre(ZZ, p, pi), p, pi);
51
T = Fl_sub(Fl_sqr_pre(M, p, pi), Fl_double(S, p), p);
52
Q[1] = T;
53
Q[2] = Fl_sub(Fl_mul_pre(M, Fl_sub(S, T, p), p, pi),
54
Fl_double(Fl_double(Fl_double(YYYY, p), p), p), p);
55
Q[3] = Fl_sub(Fl_sqr_pre(Fl_add(Y1, Z1, p), p, pi),
56
Fl_add(YY, ZZ, p), p);
57
}
58
59
INLINE void
60
Flj_dbl_pre_inplace(GEN P, ulong a4, ulong p, ulong pi)
61
{
62
Flj_dbl_indir_pre(P, P, a4, p, pi);
63
}
64
65
GEN
66
Flj_dbl_pre(GEN P, ulong a4, ulong p, ulong pi)
67
{
68
GEN Q = cgetg(4, t_VECSMALL);
69
Flj_dbl_indir_pre(P, Q, a4, p, pi);
70
return Q;
71
}
72
73
/* Cost: 11M + 5S + 9add + 4*2.
74
* http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-add-2007-bl */
75
INLINE void
76
Flj_add_indir_pre(GEN P, GEN Q, GEN R, ulong a4, ulong p, ulong pi)
77
{
78
ulong X1, Y1, Z1, X2, Y2, Z2;
79
ulong Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V, W;
80
X1 = P[1]; Y1 = P[2]; Z1 = P[3];
81
X2 = Q[1]; Y2 = Q[2]; Z2 = Q[3];
82
83
if (Z2 == 0) { R[1] = X1; R[2] = Y1; R[3] = Z1; return; }
84
if (Z1 == 0) { R[1] = X2; R[2] = Y2; R[3] = Z2; return; }
85
86
Z1Z1 = Fl_sqr_pre(Z1, p, pi);
87
Z2Z2 = Fl_sqr_pre(Z2, p, pi);
88
U1 = Fl_mul_pre(X1, Z2Z2, p, pi);
89
U2 = Fl_mul_pre(X2, Z1Z1, p, pi);
90
S1 = Fl_mul_pre(Y1, Fl_mul_pre(Z2, Z2Z2, p, pi), p, pi);
91
S2 = Fl_mul_pre(Y2, Fl_mul_pre(Z1, Z1Z1, p, pi), p, pi);
92
H = Fl_sub(U2, U1, p);
93
r = Fl_double(Fl_sub(S2, S1, p), p);
94
95
if (H == 0) {
96
if (r == 0) Flj_dbl_indir_pre(P, R, a4, p, pi); /* P = Q */
97
else { R[1] = R[2] = 1; R[3] = 0; } /* P = -Q */
98
return;
99
}
100
I = Fl_sqr_pre(Fl_double(H, p), p, pi);
101
J = Fl_mul_pre(H, I, p, pi);
102
V = Fl_mul_pre(U1, I, p, pi);
103
W = Fl_sub(Fl_sqr_pre(r, p, pi), Fl_add(J, Fl_double(V, p), p), p);
104
R[1] = W;
105
R[2] = Fl_sub(Fl_mul_pre(r, Fl_sub(V, W, p), p, pi),
106
Fl_double(Fl_mul_pre(S1, J, p, pi), p), p);
107
R[3] = Fl_mul_pre(Fl_sub(Fl_sqr_pre(Fl_add(Z1, Z2, p), p, pi),
108
Fl_add(Z1Z1, Z2Z2, p), p), H, p, pi);
109
}
110
111
INLINE void
112
Flj_add_pre_inplace(GEN P, GEN Q, ulong a4, ulong p, ulong pi)
113
{ Flj_add_indir_pre(P, Q, P, a4, p, pi); }
114
115
GEN
116
Flj_add_pre(GEN P, GEN Q, ulong a4, ulong p, ulong pi)
117
{
118
GEN R = cgetg(4, t_VECSMALL);
119
Flj_add_indir_pre(P, Q, R, a4, p, pi);
120
return R;
121
}
122
123
GEN
124
Flj_neg(GEN Q, ulong p)
125
{ return mkvecsmall3(Q[1], Fl_neg(Q[2], p), Q[3]); }
126
127
typedef struct {
128
ulong pbits, nbits; /* Positive bits and negative bits */
129
ulong lnzb; /* Leading nonzero bit */
130
} naf_t;
131
132
/* Return the signed binary representation (i.e. the Non-Adjacent Form
133
* in base 2) of a; a = x.pbits - x.nbits (+ 2^BILif < 0; this
134
* exceptional case can happen if a > 2^(BIL-1)) */
135
static void
136
naf_repr(naf_t *x, ulong a)
137
{
138
ulong pbits = 0, nbits = 0, c0 = 0, c1, a0;
139
long t, i;
140
141
for (i = 0; a; a >>= 1, ++i) {
142
a0 = a & 1;
143
c1 = (c0 + a0 + ((a & 2) >> 1)) >> 1;
144
t = c0 + a0 - (c1 << 1);
145
if (t < 0)
146
nbits |= (1UL << i);
147
else if (t > 0)
148
pbits |= (1UL << i);
149
c0 = c1;
150
}
151
c1 = c0 >> 1;
152
t = c0 - (c1 << 1);
153
/* since a >= 0, we have t >= 0; if i = BIL, pbits (virtually) overflows;
154
* that leading overflowed bit is implied and not recorded in pbits */
155
if (t > 0 && i != BITS_IN_LONG) pbits |= (1UL << i);
156
x->pbits = pbits;
157
x->nbits = nbits;
158
x->lnzb = t? i-2: i-3;
159
}
160
161
/* Standard left-to-right signed double-and-add to compute [n]P. */
162
static GEN
163
Flj_mulu_pre_naf(GEN P, ulong n, ulong a4, ulong p, ulong pi, const naf_t *x)
164
{
165
GEN R, Pi;
166
ulong pbits, nbits;
167
ulong m;
168
169
if (n == 0) return mkvecsmall3(1, 1, 0);
170
if (n == 1) return Flv_copy(P);
171
172
R = Flj_dbl_pre(P, a4, p, pi);
173
if (n == 2) return R;
174
175
pbits = x->pbits;
176
nbits = x->nbits;
177
Pi = nbits? Flj_neg(P, p): NULL;
178
m = (1UL << x->lnzb);
179
for ( ; m; m >>= 1) {
180
Flj_dbl_pre_inplace(R, a4, p, pi);
181
if (m & pbits)
182
Flj_add_pre_inplace(R, P, a4, p, pi);
183
else if (m & nbits)
184
Flj_add_pre_inplace(R, Pi, a4, p, pi);
185
}
186
return gc_const((pari_sp)R, R);
187
}
188
189
GEN
190
Flj_mulu_pre(GEN P, ulong n, ulong a4, ulong p, ulong pi)
191
{
192
naf_t x; naf_repr(&x, n);
193
return Flj_mulu_pre_naf(P, n, a4, p, pi, &x);
194
}
195
196
struct _Flj { ulong a4, p, pi; };
197
198
static GEN
199
_Flj_add(void *E, GEN P, GEN Q)
200
{
201
struct _Flj *ell=(struct _Flj *) E;
202
return Flj_add_pre(P, Q, ell->a4, ell->p, ell->pi);
203
}
204
205
static GEN
206
_Flj_mul(void *E, GEN P, GEN n)
207
{
208
struct _Flj *ell = (struct _Flj *) E;
209
long s = signe(n);
210
GEN Q;
211
if (s==0) return mkvecsmall3(1, 1, 0);
212
Q = Flj_mulu_pre(P, itou(n), ell->a4, ell->p, ell->pi);
213
return s>0 ? Q : Flj_neg(Q, ell->p);
214
}
215
static GEN
216
_Flj_one(void *E)
217
{ (void) E; return mkvecsmall3(1, 1, 0); }
218
219
GEN
220
FljV_factorback_pre(GEN P, GEN L, ulong a4, ulong p, ulong pi)
221
{
222
struct _Flj E;
223
E.a4 = a4; E.p = p; E.pi = pi;
224
return gen_factorback(P, L, (void*)&E, &_Flj_add, &_Flj_mul, &_Flj_one);
225
}
226
227
ulong
228
Flj_order_ufact(GEN P, ulong n, GEN F, ulong a4, ulong p, ulong pi)
229
{
230
pari_sp av = avma;
231
ulong res = 1;
232
long i, nfactors;
233
GEN primes, exps;
234
235
primes = gel(F, 1);
236
nfactors = lg(primes);
237
exps = gel(F, 2);
238
239
for (i = 1; i < nfactors; ++i) {
240
ulong q, pp = primes[i];
241
long j, k, ei = exps[i];
242
naf_t x;
243
GEN b;
244
245
for (q = pp, j = 1; j < ei; ++j) q *= pp;
246
b = Flj_mulu_pre(P, n / q, a4, p, pi);
247
248
naf_repr(&x, pp);
249
for (j = 0; j < ei && b[3]; ++j)
250
b = Flj_mulu_pre_naf(b, pp, a4, p, pi, &x);
251
if (b[3]) return 0;
252
for (k = 0; k < j; ++k) res *= pp;
253
set_avma(av);
254
}
255
return res;
256
}
257
258
GEN
259
Fle_to_Flj(GEN P)
260
{ return ell_is_inf(P) ? mkvecsmall3(1UL, 1UL, 0UL):
261
mkvecsmall3(P[1], P[2], 1UL);
262
}
263
264
GEN
265
Flj_to_Fle(GEN P, ulong p)
266
{
267
if (P[3] == 0) return ellinf();
268
else
269
{
270
ulong Z = Fl_inv(P[3], p);
271
ulong Z2 = Fl_sqr(Z, p);
272
ulong X3 = Fl_mul(P[1], Z2, p);
273
ulong Y3 = Fl_mul(P[2], Fl_mul(Z, Z2, p), p);
274
return mkvecsmall2(X3, Y3);
275
}
276
}
277
278
GEN
279
Flj_to_Fle_pre(GEN P, ulong p, ulong pi)
280
{
281
if (P[3] == 0) return ellinf();
282
else
283
{
284
ulong Z = Fl_inv(P[3], p);
285
ulong Z2 = Fl_sqr_pre(Z, p, pi);
286
ulong X3 = Fl_mul_pre(P[1], Z2, p, pi);
287
ulong Y3 = Fl_mul_pre(P[2], Fl_mul_pre(Z, Z2, p, pi), p, pi);
288
return mkvecsmall2(X3, Y3);
289
}
290
}
291
292
INLINE void
293
random_Fle_pre_indir(ulong a4, ulong a6, ulong p, ulong pi,
294
ulong *pt_x, ulong *pt_y)
295
{
296
ulong x, x2, y, rhs;
297
do
298
{
299
x = random_Fl(p); /* x^3+a4*x+a6 = x*(x^2+a4)+a6 */
300
x2 = Fl_sqr_pre(x, p, pi);
301
rhs = Fl_addmul_pre(a6, x, Fl_add(x2, a4, p), p, pi);
302
} while ((!rhs && !Fl_add(Fl_triple(x2,p),a4,p)) || krouu(rhs, p) < 0);
303
y = Fl_sqrt_pre(rhs, p, pi);
304
*pt_x = x; *pt_y = y;
305
}
306
307
GEN
308
random_Flj_pre(ulong a4, ulong a6, ulong p, ulong pi)
309
{
310
ulong x, y;
311
random_Fle_pre_indir(a4, a6, p, pi, &x, &y);
312
return mkvecsmall3(x, y, 1);
313
}
314
315
GEN
316
Flj_changepointinv_pre(GEN P, GEN ch, ulong p, ulong pi)
317
{
318
ulong c, u, r, s, t, u2, u3, z2;
319
ulong x = uel(P,1), y = uel(P,2), z = uel(P,3);
320
GEN w;
321
if (z == 0) return Flv_copy(P);
322
u = ch[1]; r = ch[2];
323
s = ch[3]; t = ch[4];
324
u2 = Fl_sqr_pre(u, p, pi); u3 = Fl_mul_pre(u, u2, p, pi);
325
c = Fl_mul_pre(u2, x, p, pi);
326
z2 = Fl_sqr_pre(z, p, pi);
327
w = cgetg(4, t_VECSMALL);
328
uel(w,1) = Fl_add(c, Fl_mul_pre(r, z2, p, pi), p);
329
uel(w,2) = Fl_add(Fl_mul_pre(u3 ,y, p, pi),
330
Fl_mul_pre(z, Fl_add(Fl_mul_pre(s,c,p,pi),
331
Fl_mul_pre(z2,t,p,pi), p), p, pi), p);
332
uel(w,3) = z;
333
return w;
334
}
335
336
/***********************************************************************/
337
/** **/
338
/** Fle **/
339
/** **/
340
/***********************************************************************/
341
GEN
342
Fle_changepoint(GEN P, GEN ch, ulong p)
343
{
344
ulong c, u, r, s, t, v, v2, v3;
345
GEN z;
346
if (ell_is_inf(P)) return ellinf();
347
u = ch[1]; r = ch[2];
348
s = ch[3]; t = ch[4];
349
v = Fl_inv(u, p); v2 = Fl_sqr(v,p); v3 = Fl_mul(v,v2,p);
350
c = Fl_sub(uel(P,1),r,p);
351
z = cgetg(3,t_VECSMALL);
352
z[1] = Fl_mul(v2, c, p);
353
z[2] = Fl_mul(v3, Fl_sub(uel(P,2), Fl_add(Fl_mul(s,c, p),t, p),p),p);
354
return z;
355
}
356
357
GEN
358
Fle_changepointinv(GEN P, GEN ch, ulong p)
359
{
360
ulong c, u, r, s, t, u2, u3;
361
GEN z;
362
if (ell_is_inf(P)) return ellinf();
363
u = ch[1]; r = ch[2];
364
s = ch[3]; t = ch[4];
365
u2 = Fl_sqr(u, p); u3 = Fl_mul(u,u2,p);
366
c = Fl_mul(u2,uel(P,1), p);
367
z = cgetg(3, t_VECSMALL);
368
z[1] = Fl_add(c,r,p);
369
z[2] = Fl_add(Fl_mul(u3,uel(P,2),p), Fl_add(Fl_mul(s,c,p), t, p), p);
370
return z;
371
}
372
static GEN
373
Fle_dbl_slope(GEN P, ulong a4, ulong p, ulong *slope)
374
{
375
ulong x, y, Qx, Qy;
376
if (ell_is_inf(P) || !P[2]) return ellinf();
377
x = P[1]; y = P[2];
378
*slope = Fl_div(Fl_add(Fl_triple(Fl_sqr(x,p), p), a4, p),
379
Fl_double(y, p), p);
380
Qx = Fl_sub(Fl_sqr(*slope, p), Fl_double(x, p), p);
381
Qy = Fl_sub(Fl_mul(*slope, Fl_sub(x, Qx, p), p), y, p);
382
return mkvecsmall2(Qx, Qy);
383
}
384
385
GEN
386
Fle_dbl(GEN P, ulong a4, ulong p)
387
{
388
ulong slope;
389
return Fle_dbl_slope(P,a4,p,&slope);
390
}
391
392
static GEN
393
Fle_add_slope(GEN P, GEN Q, ulong a4, ulong p, ulong *slope)
394
{
395
ulong Px, Py, Qx, Qy, Rx, Ry;
396
if (ell_is_inf(P)) return Q;
397
if (ell_is_inf(Q)) return P;
398
Px = P[1]; Py = P[2];
399
Qx = Q[1]; Qy = Q[2];
400
if (Px==Qx) return Py==Qy ? Fle_dbl_slope(P, a4, p, slope): ellinf();
401
*slope = Fl_div(Fl_sub(Py, Qy, p), Fl_sub(Px, Qx, p), p);
402
Rx = Fl_sub(Fl_sub(Fl_sqr(*slope, p), Px, p), Qx, p);
403
Ry = Fl_sub(Fl_mul(*slope, Fl_sub(Px, Rx, p), p), Py, p);
404
return mkvecsmall2(Rx, Ry);
405
}
406
407
GEN
408
Fle_add(GEN P, GEN Q, ulong a4, ulong p)
409
{
410
ulong slope;
411
return Fle_add_slope(P,Q,a4,p,&slope);
412
}
413
414
static GEN
415
Fle_neg(GEN P, ulong p)
416
{
417
if (ell_is_inf(P)) return P;
418
return mkvecsmall2(P[1], Fl_neg(P[2], p));
419
}
420
421
GEN
422
Fle_sub(GEN P, GEN Q, ulong a4, ulong p)
423
{
424
pari_sp av = avma;
425
ulong slope;
426
return gerepileupto(av, Fle_add_slope(P, Fle_neg(Q, p), a4, p, &slope));
427
}
428
429
struct _Fle { ulong a4, a6, p; };
430
431
static GEN
432
_Fle_dbl(void *E, GEN P)
433
{
434
struct _Fle *ell = (struct _Fle *) E;
435
return Fle_dbl(P, ell->a4, ell->p);
436
}
437
438
static GEN
439
_Fle_add(void *E, GEN P, GEN Q)
440
{
441
struct _Fle *ell=(struct _Fle *) E;
442
return Fle_add(P, Q, ell->a4, ell->p);
443
}
444
445
GEN
446
Fle_mulu(GEN P, ulong n, ulong a4, ulong p)
447
{
448
ulong pi;
449
if (!n || ell_is_inf(P)) return ellinf();
450
if (n==1) return zv_copy(P);
451
if (n==2) return Fle_dbl(P, a4, p);
452
pi = get_Fl_red(p);
453
return Flj_to_Fle_pre(Flj_mulu_pre(Fle_to_Flj(P), n, a4, p, pi), p, pi);
454
}
455
456
static GEN
457
_Fle_mul(void *E, GEN P, GEN n)
458
{
459
pari_sp av = avma;
460
struct _Fle *e=(struct _Fle *) E;
461
long s = signe(n);
462
GEN Q;
463
if (!s || ell_is_inf(P)) return ellinf();
464
if (s < 0) P = Fle_neg(P, e->p);
465
if (is_pm1(n)) return s > 0? zv_copy(P): P;
466
Q = (lgefint(n)==3) ? Fle_mulu(P, uel(n,2), e->a4, e->p):
467
gen_pow(P, n, (void*)e, &_Fle_dbl, &_Fle_add);
468
return s > 0? Q: gerepileuptoleaf(av, Q);
469
}
470
471
GEN
472
Fle_mul(GEN P, GEN n, ulong a4, ulong p)
473
{
474
struct _Fle E;
475
E.a4 = a4; E.p = p;
476
return _Fle_mul(&E, P, n);
477
}
478
479
/* Finds a random nonsingular point on E */
480
GEN
481
random_Fle_pre(ulong a4, ulong a6, ulong p, ulong pi)
482
{
483
ulong x, y;
484
random_Fle_pre_indir(a4, a6, p, pi, &x, &y);
485
return mkvecsmall2(x, y);
486
}
487
488
GEN
489
random_Fle(ulong a4, ulong a6, ulong p)
490
{ return random_Fle_pre(a4, a6, p, get_Fl_red(p)); }
491
492
static GEN
493
_Fle_rand(void *E)
494
{
495
struct _Fle *e=(struct _Fle *) E;
496
return random_Fle(e->a4, e->a6, e->p);
497
}
498
499
static const struct bb_group Fle_group={_Fle_add,_Fle_mul,_Fle_rand,hash_GEN,zv_equal,ell_is_inf,NULL};
500
501
GEN
502
Fle_order(GEN z, GEN o, ulong a4, ulong p)
503
{
504
pari_sp av = avma;
505
struct _Fle e;
506
e.a4=a4;
507
e.p=p;
508
return gerepileuptoint(av, gen_order(z, o, (void*)&e, &Fle_group));
509
}
510
511
GEN
512
Fle_log(GEN a, GEN b, GEN o, ulong a4, ulong p)
513
{
514
pari_sp av = avma;
515
struct _Fle e;
516
e.a4=a4;
517
e.p=p;
518
return gerepileuptoint(av, gen_PH_log(a, b, o, (void*)&e, &Fle_group));
519
}
520
521
ulong
522
Fl_ellj(ulong a4, ulong a6, ulong p)
523
{
524
if (SMALL_ULONG(p))
525
{ /* a43 = 4 a4^3 */
526
ulong a43 = Fl_double(Fl_double(Fl_mul(a4, Fl_sqr(a4, p), p), p), p);
527
/* a62 = 27 a6^2 */
528
ulong a62 = Fl_mul(Fl_sqr(a6, p), 27 % p, p);
529
ulong z1 = Fl_mul(a43, 1728 % p, p);
530
ulong z2 = Fl_add(a43, a62, p);
531
return Fl_div(z1, z2, p);
532
}
533
return Fl_ellj_pre(a4, a6, p, get_Fl_red(p));
534
}
535
536
void
537
Fl_ellj_to_a4a6(ulong j, ulong p, ulong *pt_a4, ulong *pt_a6)
538
{
539
ulong zagier = 1728 % p;
540
if (j == 0) { *pt_a4 = 0; *pt_a6 =1; }
541
else if (j == zagier) { *pt_a4 = 1; *pt_a6 =0; }
542
else
543
{
544
ulong k = Fl_sub(zagier, j, p);
545
ulong kj = Fl_mul(k, j, p);
546
ulong k2j = Fl_mul(kj, k, p);
547
*pt_a4 = Fl_triple(kj, p);
548
*pt_a6 = Fl_double(k2j, p);
549
}
550
}
551
552
ulong
553
Fl_elldisc_pre(ulong a4, ulong a6, ulong p, ulong pi)
554
{ /* D = -(4A^3 + 27B^2) */
555
ulong t1, t2;
556
t1 = Fl_mul_pre(a4, Fl_sqr_pre(a4, p, pi), p, pi);
557
t1 = Fl_double(Fl_double(t1, p), p);
558
t2 = Fl_mul_pre(27 % p, Fl_sqr_pre(a6, p, pi), p, pi);
559
return Fl_neg(Fl_add(t1, t2, p), p);
560
}
561
562
ulong
563
Fl_elldisc(ulong a4, ulong a6, ulong p)
564
{
565
if (SMALL_ULONG(p))
566
{ /* D = -(4A^3 + 27B^2) */
567
ulong t1, t2;
568
t1 = Fl_mul(a4, Fl_sqr(a4, p), p);
569
t1 = Fl_double(Fl_double(t1, p), p);
570
t2 = Fl_mul(27 % p, Fl_sqr(a6, p), p);
571
return Fl_neg(Fl_add(t1, t2, p), p);
572
}
573
return Fl_elldisc_pre(a4, a6, p, get_Fl_red(p));
574
}
575
576
void
577
Fl_elltwist_disc(ulong a4, ulong a6, ulong D, ulong p, ulong *pa4, ulong *pa6)
578
{
579
ulong D2 = Fl_sqr(D, p);
580
*pa4 = Fl_mul(a4, D2, p);
581
*pa6 = Fl_mul(a6, Fl_mul(D, D2, p), p);
582
}
583
584
void
585
Fl_elltwist(ulong a4, ulong a6, ulong p, ulong *pt_a4, ulong *pt_a6)
586
{ Fl_elltwist_disc(a4, a6, nonsquare_Fl(p), p, pt_a4, pt_a6); }
587
588
static void
589
Fle_dbl_sinv_pre_inplace(GEN P, ulong a4, ulong sinv, ulong p, ulong pi)
590
{
591
ulong x, y, slope;
592
if (uel(P,1)==p) return;
593
if (!P[2]) { P[1] = p; return; }
594
x = P[1]; y = P[2];
595
slope = Fl_mul_pre(Fl_add(Fl_triple(Fl_sqr_pre(x, p, pi), p), a4, p),
596
sinv, p, pi);
597
P[1] = Fl_sub(Fl_sqr_pre(slope, p, pi), Fl_double(x, p), p);
598
P[2] = Fl_sub(Fl_mul_pre(slope, Fl_sub(x, P[1], p), p, pi), y, p);
599
}
600
601
static void
602
Fle_add_sinv_pre_inplace(GEN P, GEN Q, ulong a4, ulong sinv, ulong p, ulong pi)
603
{
604
ulong Px, Py, Qx, Qy, slope;
605
if (uel(P,1)==p) { P[1] = Q[1]; P[2] = Q[2]; }
606
if (ell_is_inf(Q)) return;
607
Px = P[1]; Py = P[2];
608
Qx = Q[1]; Qy = Q[2];
609
if (Px==Qx)
610
{
611
if (Py==Qy) Fle_dbl_sinv_pre_inplace(P, a4, sinv, p, pi);
612
else P[1] = p;
613
return;
614
}
615
slope = Fl_mul_pre(Fl_sub(Py, Qy, p), sinv, p, pi);
616
P[1] = Fl_sub(Fl_sub(Fl_sqr_pre(slope, p, pi), Px, p), Qx, p);
617
P[2] = Fl_sub(Fl_mul_pre(slope, Fl_sub(Px, P[1], p), p, pi), Py, p);
618
}
619
620
static void
621
Fle_sub_sinv_pre_inplace(GEN P, GEN Q, ulong a4, ulong sinv, ulong p, ulong pi)
622
{
623
ulong Px, Py, Qx, Qy, slope;
624
if (uel(P,1)==p) { P[1] = Q[1]; P[2] = Fl_neg(Q[2], p); }
625
if (ell_is_inf(Q)) return;
626
Px = P[1]; Py = P[2];
627
Qx = Q[1]; Qy = Q[2];
628
if (Px==Qx)
629
{
630
if (Py==Qy) P[1] = p;
631
else
632
Fle_dbl_sinv_pre_inplace(P, a4, sinv, p, pi);
633
return;
634
}
635
slope = Fl_mul_pre(Fl_add(Py, Qy, p), sinv, p, pi);
636
P[1] = Fl_sub(Fl_sub(Fl_sqr_pre(slope, p, pi), Px, p), Qx, p);
637
P[2] = Fl_sub(Fl_mul_pre(slope, Fl_sub(Px, P[1], p), p, pi), Py, p);
638
}
639
640
static long
641
skipzero(long n) { return n ? n:1; }
642
643
void
644
FleV_add_pre_inplace(GEN P, GEN Q, GEN a4, ulong p, ulong pi)
645
{
646
long i, l=lg(a4);
647
GEN sinv = cgetg(l, t_VECSMALL);
648
for(i=1; i<l; i++)
649
uel(sinv,i) = umael(P,i,1)==p? 1: skipzero(Fl_sub(mael(P,i,1), mael(Q,i,1), p));
650
Flv_inv_pre_inplace(sinv, p, pi);
651
for (i=1; i<l; i++)
652
Fle_add_sinv_pre_inplace(gel(P,i), gel(Q,i), uel(a4,i), uel(sinv,i), p, pi);
653
}
654
655
void
656
FleV_sub_pre_inplace(GEN P, GEN Q, GEN a4, ulong p, ulong pi)
657
{
658
long i, l=lg(a4);
659
GEN sinv = cgetg(l, t_VECSMALL);
660
for(i=1; i<l; i++)
661
uel(sinv,i) = umael(P,i,1)==p? 1: skipzero(Fl_sub(mael(P,i,1), mael(Q,i,1), p));
662
Flv_inv_pre_inplace(sinv, p, pi);
663
for (i=1; i<l; i++)
664
Fle_sub_sinv_pre_inplace(gel(P,i), gel(Q,i), uel(a4,i), uel(sinv,i), p, pi);
665
}
666
667
void
668
FleV_dbl_pre_inplace(GEN P, GEN a4, ulong p, ulong pi)
669
{
670
long i, l=lg(a4);
671
GEN sinv = cgetg(l, t_VECSMALL);
672
for(i=1; i<l; i++)
673
uel(sinv,i) = umael(P,i,1)==p? 1: skipzero(Fl_double(umael(P,i,2), p));
674
Flv_inv_pre_inplace(sinv, p, pi);
675
for(i=1; i<l; i++)
676
Fle_dbl_sinv_pre_inplace(gel(P,i), uel(a4,i), uel(sinv,i), p, pi);
677
}
678
679
static void
680
FleV_mulu_pre_naf_inplace(GEN P, ulong n, GEN a4, ulong p, ulong pi, const naf_t *x)
681
{
682
pari_sp av = avma;
683
ulong pbits, nbits, m;
684
GEN R;
685
if (n == 1) return;
686
687
R = P; P = gcopy(P);
688
FleV_dbl_pre_inplace(R, a4, p, pi);
689
if (n == 2) return;
690
691
pbits = x->pbits;
692
nbits = x->nbits;
693
m = (1UL << x->lnzb);
694
for ( ; m; m >>= 1) {
695
FleV_dbl_pre_inplace(R, a4, p, pi);
696
if (m & pbits)
697
FleV_add_pre_inplace(R, P, a4, p, pi);
698
else if (m & nbits)
699
FleV_sub_pre_inplace(R, P, a4, p, pi);
700
}
701
set_avma(av);
702
}
703
704
void
705
FleV_mulu_pre_inplace(GEN P, ulong n, GEN a4, ulong p, ulong pi)
706
{
707
naf_t x; naf_repr(&x, n);
708
FleV_mulu_pre_naf_inplace(P, n, a4, p, pi, &x);
709
}
710
711
/***********************************************************************/
712
/** **/
713
/** Pairings **/
714
/** **/
715
/***********************************************************************/
716
717
/* Derived from APIP from and by Jerome Milan, 2012 */
718
719
static ulong
720
Fle_vert(GEN P, GEN Q, ulong a4, ulong p)
721
{
722
if (ell_is_inf(P))
723
return 1;
724
if (uel(Q, 1) != uel(P, 1))
725
return Fl_sub(uel(Q, 1), uel(P, 1), p);
726
if (uel(P,2) != 0 ) return 1;
727
return Fl_inv(Fl_add(Fl_triple(Fl_sqr(uel(P,1),p), p), a4, p), p);
728
}
729
730
static ulong
731
Fle_Miller_line(GEN R, GEN Q, ulong slope, ulong a4, ulong p)
732
{
733
ulong x = uel(Q, 1), y = uel(Q, 2);
734
ulong tmp1 = Fl_sub(x, uel(R, 1), p);
735
ulong tmp2 = Fl_add(Fl_mul(tmp1, slope, p), uel(R,2), p);
736
if (y != tmp2)
737
return Fl_sub(y, tmp2, p);
738
if (y == 0)
739
return 1;
740
else
741
{
742
ulong s1, s2;
743
ulong y2i = Fl_inv(Fl_double(y, p), p);
744
s1 = Fl_mul(Fl_add(Fl_triple(Fl_sqr(x, p), p), a4, p), y2i, p);
745
if (s1 != slope)
746
return Fl_sub(s1, slope, p);
747
s2 = Fl_mul(Fl_sub(Fl_triple(x, p), Fl_sqr(s1, p), p), y2i, p);
748
return s2 ? s2: y2i;
749
}
750
}
751
752
/* Computes the equation of the line tangent to R and returns its
753
evaluation at the point Q. Also doubles the point R.
754
*/
755
756
static ulong
757
Fle_tangent_update(GEN R, GEN Q, ulong a4, ulong p, GEN *pt_R)
758
{
759
if (ell_is_inf(R))
760
{
761
*pt_R = ellinf();
762
return 1;
763
}
764
else if (uel(R,2) == 0)
765
{
766
*pt_R = ellinf();
767
return Fle_vert(R, Q, a4, p);
768
} else {
769
ulong slope;
770
*pt_R = Fle_dbl_slope(R, a4, p, &slope);
771
return Fle_Miller_line(R, Q, slope, a4, p);
772
}
773
}
774
775
/* Computes the equation of the line through R and P, and returns its
776
evaluation at the point Q. Also adds P to the point R.
777
*/
778
779
static ulong
780
Fle_chord_update(GEN R, GEN P, GEN Q, ulong a4, ulong p, GEN *pt_R)
781
{
782
if (ell_is_inf(R))
783
{
784
*pt_R = gcopy(P);
785
return Fle_vert(P, Q, a4, p);
786
}
787
else if (ell_is_inf(P))
788
{
789
*pt_R = gcopy(R);
790
return Fle_vert(R, Q, a4, p);
791
}
792
else if (uel(P, 1) == uel(R, 1))
793
{
794
if (uel(P, 2) == uel(R, 2))
795
return Fle_tangent_update(R, Q, a4, p, pt_R);
796
else {
797
*pt_R = ellinf();
798
return Fle_vert(R, Q, a4, p);
799
}
800
} else {
801
ulong slope;
802
*pt_R = Fle_add_slope(P, R, a4, p, &slope);
803
return Fle_Miller_line(R, Q, slope, a4, p);
804
}
805
}
806
807
struct _Fle_miller { ulong p, a4; GEN P; };
808
static GEN
809
Fle_Miller_dbl(void* E, GEN d)
810
{
811
struct _Fle_miller *m = (struct _Fle_miller *)E;
812
ulong p = m->p, a4 = m->a4;
813
GEN P = m->P;
814
ulong v, line;
815
ulong N = Fl_sqr(umael(d,1,1), p);
816
ulong D = Fl_sqr(umael(d,1,2), p);
817
GEN point = gel(d,2);
818
line = Fle_tangent_update(point, P, a4, p, &point);
819
N = Fl_mul(N, line, p);
820
v = Fle_vert(point, P, a4, p);
821
D = Fl_mul(D, v, p); return mkvec2(mkvecsmall2(N, D), point);
822
}
823
static GEN
824
Fle_Miller_add(void* E, GEN va, GEN vb)
825
{
826
struct _Fle_miller *m = (struct _Fle_miller *)E;
827
ulong p = m->p, a4= m->a4;
828
GEN P = m->P, point;
829
ulong v, line;
830
ulong na = umael(va,1,1), da = umael(va,1,2);
831
ulong nb = umael(vb,1,1), db = umael(vb,1,2);
832
GEN pa = gel(va,2), pb = gel(vb,2);
833
ulong N = Fl_mul(na, nb, p);
834
ulong D = Fl_mul(da, db, p);
835
line = Fle_chord_update(pa, pb, P, a4, p, &point);
836
N = Fl_mul(N, line, p);
837
v = Fle_vert(point, P, a4, p);
838
D = Fl_mul(D, v, p); return mkvec2(mkvecsmall2(N, D), point);
839
}
840
841
/* Returns the Miller function f_{m, Q} evaluated at the point P using
842
* the standard Miller algorithm. */
843
static ulong
844
Fle_Miller(GEN Q, GEN P, ulong m, ulong a4, ulong p)
845
{
846
pari_sp av = avma;
847
struct _Fle_miller d;
848
GEN v;
849
ulong N, D;
850
851
d.a4 = a4; d.p = p; d.P = P;
852
v = gen_powu_i(mkvec2(mkvecsmall2(1,1), Q), m, (void*)&d,
853
Fle_Miller_dbl, Fle_Miller_add);
854
N = umael(v,1,1); D = umael(v,1,2);
855
return gc_ulong(av, Fl_div(N, D, p));
856
}
857
858
ulong
859
Fle_weilpairing(GEN P, GEN Q, ulong m, ulong a4, ulong p)
860
{
861
pari_sp ltop = avma;
862
ulong N, D, w;
863
if (ell_is_inf(P) || ell_is_inf(Q) || zv_equal(P,Q)) return 1;
864
N = Fle_Miller(P, Q, m, a4, p);
865
D = Fle_Miller(Q, P, m, a4, p);
866
w = Fl_div(N, D, p);
867
if (odd(m)) w = Fl_neg(w, p);
868
return gc_ulong(ltop, w);
869
}
870
871
ulong
872
Fle_tatepairing(GEN P, GEN Q, ulong m, ulong a4, ulong p)
873
{
874
if (ell_is_inf(P) || ell_is_inf(Q)) return 1;
875
return Fle_Miller(P, Q, m, a4, p);
876
}
877
878
GEN
879
Fl_ellptors(ulong l, ulong N, ulong a4, ulong a6, ulong p)
880
{
881
long v = z_lval(N, l);
882
ulong N0, N1;
883
GEN F;
884
if (v==0) return cgetg(1,t_VEC);
885
N0 = upowuu(l, v); N1 = N/N0;
886
F = mkmat2(mkcols(l), mkcols(v));
887
while(1)
888
{
889
pari_sp av2 = avma;
890
GEN P, Q;
891
ulong d, s, t;
892
893
P = Fle_mulu(random_Fle(a4, a6, p), N1, a4, p);
894
Q = Fle_mulu(random_Fle(a4, a6, p), N1, a4, p);
895
s = itou(Fle_order(P, F, a4, p));
896
t = itou(Fle_order(Q, F, a4, p));
897
if (s < t) { swap(P,Q); lswap(s,t); }
898
if (s == N0) retmkvec(Fle_mulu(P, s/l, a4, p));
899
d = Fl_order(Fle_weilpairing(P, Q, s, a4, p), s, p);
900
if (s*d == N0)
901
retmkvec2(Fle_mulu(P, s/l, a4, p), Fle_mulu(Q, t/l, a4, p));
902
set_avma(av2);
903
}
904
}
905
906