Commit d465ab3b authored by Peter Bruin's avatar Peter Bruin

substantial improvements inspired by Mascot's paper on Hensel-lifting torsion points

parent 3da06ab8
......@@ -100,54 +100,30 @@ curve_divisor_IGS (GEN X, GEN W_D, unsigned long i) {
multiplication by s induces a map V1 -> V2, return
the induced map on quotient spaces.
*/
GEN
curve_divisor_section_as_matrix (GEN X, GEN s, GEN V1, GEN V2,
GEN Q1, GEN Q2) {
static GEN
curve_divisor_section_as_matrix(GEN X, GEN s, GEN C1, GEN piv2, GEN R2) {
unsigned long p = curve_base_field_characteristic(X);
GEN T = curve_base_field_polynomial(X);
pari_sp av = avma;
GEN s_V1 = curve_multiply_section_subspace(X, s, V1);
GEN M = matsmall_solve(V2, s_V1, p, T);
M = matsmall_solve_left(Q1, matsmall_mul(Q2, M, p, T), p, T);
GEN s_C1 = curve_multiply_section_subspace(X, s, C1);
GEN M = matsmall_mul(R2, rowpermute(s_C1, piv2), p, T);
return gerepileupto(av, M);
}
/*
Given an effective divisor D on X, three subspaces
V_1, V_2, V_3 of space of the form \Gamma(X,{\cal L}^i)
such that V_3 is the product of V_1 and V_2, and quotient
maps to the corresponding spaces \Gamma(D,{\cal L}^i),
return the bilinear map Q_1 \times Q_2 \to Q_3.
such that V_3 is the product of V_1 and V_2, return
the induced map on quotient spaces.
*/
GEN
curve_divisor_bilinear_map (GEN X, GEN V1, GEN V2, GEN V3,
GEN Q1, GEN Q2, GEN Q3) {
unsigned long p = curve_base_field_characteristic(X);
GEN T = curve_base_field_polynomial(X);
GEN sol, basis, mu;
long i, n;
static GEN
curve_divisor_bilinear_map(GEN X, GEN C1, GEN C2, GEN piv3, GEN R3) {
long i, n = lg(C1) - 1;
pari_sp av = avma;
if(lg(Q1) <= 1 || lg(Q2) <= 1 || lg(Q3) <= 1)
pari_err_DIM("curve_divisor_bilinear_map");
n = lg(gel(Q1, 1)) - 1;
if(lg(gel(Q2, 1)) - 1 != n || lg(gel(Q3, 1)) - 1 != n)
pari_err_DIM("curve_divisor_bilinear_map");
/*
Compute a set of vectors in \Gamma(X,{\cal L}) mapping to the
standard basis vectors of \Gamma(D,i^*{\cal L}).
*/
Q1 = matsmall_to_RgM(Q1, p, T);
sol = RgM_invimage(Q1, matid(n));
sol = RgM_to_matsmall(sol, p, T);
basis = matsmall_mul(V1, sol, p, T);
mu = cgetg(n + 1, t_VEC);
GEN mu = cgetg(n + 1, t_VEC);
for (i = 1; i <= n; i++)
gel(mu, i) = curve_divisor_section_as_matrix(X, gel(basis, i),
V2, V3, Q2, Q3);
gel(mu, i) = curve_divisor_section_as_matrix(X, gel(C1, i),
C2, piv3, R3);
return gerepileupto(av, mu);
}
......@@ -172,26 +148,27 @@ curve_divisor_algebra (GEN X, GEN W_D, GEN W_2_D,
unsigned long p = curve_base_field_characteristic(X);
GEN T = curve_base_field_polynomial(X);
GEN V = curve_V(X, d);
GEN V_2 = curve_V(X, 2 * d);
GEN Q = matsmall_quotient(V, W_D, p, T);
GEN Q_2 = matsmall_quotient(V_2, W_2_D, p, T);
GEN piv2 = curve_pivots_V(X, 2 * d);
GEN R_2 = matsmall_coker(rowpermute(W_2_D, piv2), p, T);
GEN C;
GEN algebra, basis;
int try_monogenic = 1; /* TODO: useful criterion */
if (try_monogenic) {
GEN s, t, M, N, A, v;
GEN s, t, M, N, A = NULL, v;
long deg_D = lg(V) - lg(W_D), i;
int done = 0;
while (1) {
s = curve_random_section(X, V);
M = curve_divisor_section_as_matrix(X, s, V, V_2, Q, Q_2);
if (matsmall_rank(M, p, T) == deg_D)
break;
}
while (!done) {
if (A == NULL) {
C = matsmall_random_subspace(V, deg_D, 0, p, T);
s = curve_random_section(X, V);
M = curve_divisor_section_as_matrix(X, s, C, piv2, R_2);
}
t = curve_random_section(X, V);
N = curve_divisor_section_as_matrix(X, t, V, V_2, Q, Q_2);
N = curve_divisor_section_as_matrix(X, t, C, piv2, R_2);
A = matsmall_solve(M, N, p, T);
if (A == NULL)
continue;
algebra = matsmall_charpoly(A, 0, p, T);
while (1) {
basis = cgetg(deg_D + 1, t_MAT);
......@@ -208,18 +185,19 @@ curve_divisor_algebra (GEN X, GEN W_D, GEN W_2_D,
}
}
} else {
GEN mu = curve_divisor_bilinear_map(X, V, V, V_2, Q, Q, Q_2);
GEN mu, algebra_basis;
C = matsmall_complement(V, W_D, p, T);
mu = curve_divisor_bilinear_map(X, C, C, piv2, R_2);
/*
Compute the algebra \Gamma(D,\O_D) and its action
on \Gamma(D,i^*{\cal L}).
*/
GEN algebra_basis = symmetric_bilinear_map_to_algsmall(mu, p, T);
algebra_basis = symmetric_bilinear_map_to_algsmall(mu, p, T);
algebra = gel(algebra_basis, 1);
basis = gel(algebra_basis, 2);
}
/* Compute the quotient in terms of the good basis. */
Q = matsmall_solve(basis, Q, p, T);
return gerepilecopy(av, mkvec2(algebra, Q));
C = matsmall_mul(C, basis, p, T);
return gerepilecopy(av, mkvec2(algebra, C));
}
GEN
......@@ -298,7 +276,7 @@ curve_decompose_divisor (GEN X, GEN W_D, GEN W_2_D,
GEN V = curve_V (X, d);
long i, l;
pari_sp av;
GEN alg_Q, algebra, Q;
GEN alg_C, algebra, C;
GEN ideals_mult, ideals, points, multiplicities;
if(lg(W_D) == lg(V)) {
......@@ -309,18 +287,16 @@ curve_decompose_divisor (GEN X, GEN W_D, GEN W_2_D,
}
av = avma;
alg_Q = curve_divisor_algebra(X, W_D, W_2_D, d);
algebra = gel(alg_Q, 1);
Q = gel(alg_Q, 2);
alg_C = curve_divisor_algebra(X, W_D, W_2_D, d);
algebra = gel(alg_C, 1);
C = gel(alg_C, 2);
ideals_mult = algebra_decompose(algebra, p, T);
ideals = gel(ideals_mult, 1);
multiplicities = gel(ideals_mult, 2);
points = cgetg_copy(ideals, &l);
for (i = 1; i < l; i++) {
GEN tmp = matsmall_inverse_image(Q, gel(ideals, i), p, T);
gel(points, i) = matsmall_mul(V, tmp, p, T);
}
for (i = 1; i < l; i++)
gel(points, i) = shallowconcat(W_D, matsmall_mul(C, gel(ideals, i), p, T));
return gerepilecopy(av, mkvec2(points, multiplicities));
}
......
......@@ -5,10 +5,6 @@ GEN curve_divisor_to_point (GEN X, GEN P);
GEN curve_point_to_divisor (GEN X, GEN P);
GEN curve_point_multiples (GEN X, GEN P);
GEN curve_divisor_IGS (GEN X, GEN W_D, unsigned long i);
GEN curve_divisor_section_as_matrix (GEN X, GEN s, GEN V1, GEN V2,
GEN Q1, GEN Q2);
GEN curve_divisor_bilinear_map (GEN X, GEN V1, GEN V2, GEN V3,
GEN Q1, GEN Q2, GEN Q3);
GEN curve_divisor_algebra (GEN X, GEN W_D, GEN W_2_D,
unsigned long d);
GEN curve_decompose_divisor (GEN X, GEN W_D, GEN W_2_D,
......
......@@ -260,7 +260,7 @@ jacobian_equal (GEN X, GEN W_D, GEN W_E) {
If s != NULL, return a section with divisor D + E + F in *s.
*/
GEN
jacobian_addflip_cert (GEN X, GEN W_D, GEN W_E, GEN *s) {
jacobian_addflip_cert(GEN X, GEN W_D, GEN W_E, GEN *s, int random) {
GEN V = jacobian_V (X);
GEN t, W_F;
pari_sp av = avma;
......@@ -274,7 +274,7 @@ jacobian_addflip_cert (GEN X, GEN W_D, GEN W_E, GEN *s) {
GEN W0_3_D_E = curve_divide_subspaces (X, W_2_D_E, 4,
jacobian_IGS_V_0 (X), 1);
GEN W0_5_D_E_F;
t = gel(W0_3_D_E, 1);
t = random ? curve_random_section(X, W0_3_D_E) : gel(W0_3_D_E, 1);
W0_5_D_E_F = curve_multiply_section_subspace(X, t, V);
W_F = curve_divide_subspaces(X, W0_5_D_E_F, 5,
jacobian_deflate (X, W0_3_D_E), 3);
......@@ -289,7 +289,7 @@ jacobian_addflip_cert (GEN X, GEN W_D, GEN W_E, GEN *s) {
if (jacobian_divisor_small (X, W_D)
&& jacobian_divisor_small (X, W_E)) {
GEN W_D_flip, W_D_E;
t = gel(W_D, 1);
t = random ? curve_random_section(X, W_D) : gel(W_D, 1);
W_D_flip = jacobian_flip(X, W_D, t);
W_D_E = curve_divide_subspaces(X, curve_multiply_section_subspace(X, t, W_E), 6,
jacobian_deflate(X, W_D_flip), 3);
......@@ -319,7 +319,7 @@ jacobian_addflip_cert (GEN X, GEN W_D, GEN W_E, GEN *s) {
GEN
jacobian_addflip (GEN X, GEN W_D, GEN W_E) {
return jacobian_addflip_cert (X, W_D, W_E, NULL);
return jacobian_addflip_cert(X, W_D, W_E, NULL, 0);
}
GEN
......
......@@ -38,7 +38,7 @@ int jacobian_is_zero (GEN X, GEN W_D);
int jacobian_is_zero_cert (GEN X, GEN W_D, GEN *s);
int jacobian_equal (GEN X, GEN W_D, GEN W_E);
GEN jacobian_addflip (GEN X, GEN W_D, GEN W_E);
GEN jacobian_addflip_cert (GEN X, GEN W_D, GEN W_E, GEN *s);
GEN jacobian_addflip_cert(GEN X, GEN W_D, GEN W_E, GEN *s, int random);
GEN jacobian_negate (GEN X, GEN W_D);
GEN jacobian_add (GEN X, GEN W_D, GEN W_E);
GEN jacobian_subtract (GEN X, GEN W_D, GEN W_E);
......
......@@ -10,167 +10,50 @@
static GEN
norm_of_section(GEN X, GEN s, GEN V1, GEN V2, GEN Q1, GEN Q2) {
norm_of_section(GEN X, GEN s, GEN C1, GEN piv2, GEN R2) {
unsigned long p = curve_base_field_characteristic(X);
GEN T = curve_base_field_polynomial(X);
GEN M = curve_divisor_section_as_matrix(X, s, V1, V2, Q1, Q2);
GEN s_C1 = curve_multiply_section_subspace(X, s, C1);
GEN M = matsmall_mul(R2, rowpermute(s_C1, piv2), p, T);
return matsmall_det(M, p, T);
}
/*
Linearity of the norm functor
(thesis, Algorithm IV.2.9, simplified).
*/
static GEN
norm_functor_linearity(GEN X, long i, long j,
GEN W_2_E, GEN W_i_2_D1,
GEN W_j_2_D2, GEN W_i_j_2_D1_D2,
GEN Q_2, GEN Q_i_2_D1,
GEN Q_j_2_D2, GEN Q_i_j_2_D1_D2) {
static int
divisors_disjoint(GEN X, GEN W_D, GEN W_E) {
unsigned long p = curve_base_field_characteristic(X);
GEN T = curve_base_field_polynomial(X);
GEN V_2 = curve_V(X, 2);
GEN W_j_4_D2, W_i_j_4_D1_D2;
GEN W_j_4_D2_E, W_i_j_4_D1_D2_E;
GEN Q_j_4_D2, Q_i_j_4_D1_D2;
GEN beta0, beta2;
GEN delta0, delta1, delta2, delta3;
GEN lambda;
pari_sp av = avma;
W_j_4_D2 = curve_multiply_subspaces(X, V_2, W_j_2_D2);
W_i_j_4_D1_D2 = curve_multiply_subspaces(X, V_2, W_i_j_2_D1_D2);
W_j_4_D2_E = curve_multiply_subspaces(X, W_2_E, W_j_2_D2);
W_i_j_4_D1_D2_E = curve_multiply_subspaces(X, W_2_E, W_i_j_2_D1_D2);
Q_j_4_D2 = matsmall_quotient(W_j_4_D2, W_j_4_D2_E, p, T);
Q_i_j_4_D1_D2 = matsmall_quotient(W_i_j_4_D1_D2, W_i_j_4_D1_D2_E, p, T);
do {
beta0 = curve_random_section(X, V_2);
delta0 = norm_of_section(X, beta0, W_j_2_D2, W_j_4_D2,
Q_j_2_D2, Q_j_4_D2);
} while (gequal0(delta0));
delta1 = norm_of_section(X, beta0, W_i_j_2_D1_D2, W_i_j_4_D1_D2,
Q_i_j_2_D1_D2, Q_i_j_4_D1_D2);
do {
beta2 = curve_random_section(X, W_j_2_D2);
delta2 = norm_of_section(X, beta2, V_2, W_j_4_D2,
Q_2, Q_j_4_D2);
} while (gequal0(delta2));
delta3 = norm_of_section(X, beta2, W_i_2_D1, W_i_j_4_D1_D2,
Q_i_2_D1, Q_i_j_4_D1_D2);
lambda = gdiv(gmul(delta0, delta3),
gmul(delta1, delta2));
return gerepileupto(av, lambda);
GEN W_F;
W_D = curve_multiply_subspaces(X, W_D, curve_V(X, 1));
W_E = curve_multiply_subspaces(X, W_E, curve_V(X, 1));
W_F = matsmall_image(shallowconcat(W_D, W_E), p, T);
return curve_divisor_degree(X, W_F, 3) == 0;
}
static void
quotient_maps(GEN X, GEN D, GEN W_E, GEN *W3_D, GEN *Q3_D) {
unsigned long p = curve_base_field_characteristic(X);
GEN T = curve_base_field_polynomial(X);
long l, m = lg(D) - 2;
GEN W3_Dl, W4_Dl_E, W3_Dl_E;
*W3_D = cgetg(m + 2, t_VEC);
*Q3_D = cgetg(m + 2, t_VEC);
for (l = 0; l <= m; l++) {
W3_Dl = curve_multiply_subspaces(X, curve_V(X, 1), gel(D, l + 1));
W4_Dl_E = curve_multiply_subspaces(X, gel(D, l + 1), W_E);
W3_Dl_E = curve_divide_subspaces(X, W4_Dl_E, 4,
curve_IGS_V(X, 1), 1);
gel(*W3_D, l + 1) = W3_Dl;
gel(*Q3_D, l + 1) = matsmall_quotient(W3_Dl, W3_Dl_E, p, T);
static int
all_disjoint(GEN X, GEN W_D, GEN W_E) {
long i;
for (i = 1; i < lg(W_E); i++) {
if (!divisors_disjoint(X, W_D, gel(W_E, i)))
return 0;
}
return 1;
}
static GEN
compute_gamma(GEN X, GEN D, GEN c, GEN W_E, GEN s, GEN W2, GEN Q2,
GEN W3_D, GEN Q3_D, GEN gamma_0, GEN gamma_1) {
unsigned long p = curve_base_field_characteristic(X);
GEN T = curve_base_field_polynomial(X);
long i, j, l, m = lg(c);
GEN Q4_Di_Dj, Q5_Di_Dj_Dl;
GEN W6_Di_Dj_Dl, W5_Di_Dj_Dl;
GEN W4_Di_Dj, W6_Di_Dj_E, W4_Di_Dj_E;
GEN W7_Di_Dj_Dl_E, W5_Di_Dj_Dl_E;
GEN gamma, lambda1, lambda2, lambda, M;
gamma = cgetg(m + 2, t_VEC);
gel(gamma, 1) = gamma_0;
gel(gamma, 2) = gamma_1;
for (l = 2; l <= m; l++) {
i = mael(c, l - 1, 1);
j = mael(c, l - 1, 2);
W4_Di_Dj = curve_multiply_subspaces(X, gel(D, i + 1), gel(D, j + 1));
W6_Di_Dj_E = curve_multiply_subspaces(X, W4_Di_Dj, W_E);
W4_Di_Dj_E = curve_divide_subspaces(X, W6_Di_Dj_E, 6,
curve_IGS_V(X, 2), 2);
Q4_Di_Dj = matsmall_quotient(W4_Di_Dj, W4_Di_Dj_E, p, T);
lambda1 = norm_functor_linearity(X, 1, 1, W_E,
gel(W3_D, i + 1),
gel(W3_D, j + 1),
W4_Di_Dj,
Q2,
gel(Q3_D, i + 1),
gel(Q3_D, j + 1),
Q4_Di_Dj);
W6_Di_Dj_Dl = curve_multiply_subspaces(X, W4_Di_Dj, gel(D, l + 1));
W5_Di_Dj_Dl = curve_divide_subspaces(X, W6_Di_Dj_Dl, 6,
curve_IGS_V(X, 1), 1);
W7_Di_Dj_Dl_E = curve_multiply_subspaces(X, W5_Di_Dj_Dl, W_E);
W5_Di_Dj_Dl_E = curve_divide_subspaces(X, W7_Di_Dj_Dl_E, 7,
curve_IGS_V(X, 2), 2);
Q5_Di_Dj_Dl = matsmall_quotient(W5_Di_Dj_Dl, W5_Di_Dj_Dl_E, p, T);
M = curve_divisor_section_as_matrix(X, gel(s, l - 1),
W2, W5_Di_Dj_Dl,
Q2, Q5_Di_Dj_Dl);
Q5_Di_Dj_Dl = matsmall_solve(M, Q5_Di_Dj_Dl, p, T);
lambda2 = norm_functor_linearity(X, 2, 1, W_E,
W4_Di_Dj,
gel(W3_D, l + 1),
W5_Di_Dj_Dl,
Q2,
Q4_Di_Dj,
gel(Q3_D, l + 1),
Q5_Di_Dj_Dl);
lambda = gmul(lambda1, lambda2);
gel(gamma, l + 1) = gdiv(lambda, gmul(gel(gamma, i + 1),
gel(gamma, j + 1)));
}
return gamma;
}
/*
Compute isomorphisms of the form I^E_{s,t}
(thesis, Algorithm IV.3.8).
*/
static GEN
iso(GEN X, GEN c, GEN D, GEN W_E, GEN s, GEN u, GEN v) {
unsigned long p = curve_base_field_characteristic(X);
GEN T = curve_base_field_polynomial(X);
long m = lg(c);
GEN W2, Q2, W3_D, Q3_D;
GEN gamma, delta, M;
pari_sp av = avma;
W2 = curve_V(X, 2);
Q2 = matsmall_quotient(W2, W_E, p, T);
quotient_maps(X, D, W_E, &W3_D, &Q3_D);
/* normalise the data for D_0 */
M = curve_divisor_section_as_matrix(X, u, W2, gel(W3_D, 1),
Q2, gel(Q3_D, 1));
gel(Q3_D, 1) = matsmall_solve(M, gel(Q3_D, 1), p, T);
static void
find_disjoint_divisors(GEN J, GEN W_D, GEN *W_E, GEN *u_D0,
GEN *W_D0, GEN *u_E0, GEN *W_E0) {
while (!divisors_disjoint(J, W_D, *W_E))
*W_E = jacobian_random_presentation(J, *W_E);
gamma = compute_gamma(X, D, c, W_E, s, W2, Q2, W3_D, Q3_D,
gen_1, gen_1);
delta = norm_of_section(X, v, W2, gel(W3_D, m + 1),
Q2, gel(Q3_D, m + 1));
return gerepileupto(av, ginv(gmul(gel(gamma, m + 1), delta)));
do {
*u_D0 = curve_random_section(J, curve_V(J, 1));
*W_D0 = curve_multiply_section_subspace(J, *u_D0, curve_V(J, 1));
} while (!divisors_disjoint(J, *W_D0, *W_E));
do {
*u_E0 = curve_random_section(J, curve_V(J, 1));
*W_E0 = curve_multiply_section_subspace(J, *u_E0, curve_V(J, 1));
} while (!divisors_disjoint(J, *W_E0, W_D)
|| !divisors_disjoint(J, *W_E0, *W_D0));
}
/*
......@@ -187,8 +70,9 @@ iso(GEN X, GEN c, GEN D, GEN W_E, GEN s, GEN u, GEN v) {
*/
static void
torsion_data(GEN J, GEN W_D, GEN W_D0, GEN c,
GEN *D, GEN *s, GEN *v) {
GEN *D, GEN *s, GEN *v, GEN W_avoid) {
long i, j, l, m = lg(c);
int random = (W_avoid != NULL);
*D = cgetg(m + 2, t_VEC);
*s = cgetg(m, t_VEC);
......@@ -197,13 +81,57 @@ torsion_data(GEN J, GEN W_D, GEN W_D0, GEN c,
for (l = 2; l <= m; l++) {
i = mael(c, l - 1, 1);
j = mael(c, l - 1, 2);
gel(*D, l + 1) = jacobian_addflip_cert(J, gel(*D, i + 1), gel(*D, j + 1),
&gel(*s, l - 1));
do {
gel(*D, l + 1) = jacobian_addflip_cert(J, gel(*D, i + 1), gel(*D, j + 1),
&gel(*s, l - 1), random);
} while (random && !all_disjoint(J, gel(*D, l + 1), W_avoid));
}
if (!jacobian_is_zero_cert(J, gel(*D, m + 1), v))
pari_err(e_MISC, "inconsistent: line bundle is non-trivial");
}
static GEN
eval_half(GEN X, GEN c, GEN u, GEN D, GEN s, GEN v, GEN W_E) {
unsigned long p = curve_base_field_characteristic(X);
GEN T = curve_base_field_polynomial(X);
long i, j, l, m = lg(c);
GEN u3, W2, C2, piv3, W3_E, R3, piv5, W5_E, R5, gamma, sigma, tau;
W2 = curve_V(X, 2);
C2 = matsmall_complement(W2, W_E, p, T);
piv3 = curve_pivots_V(X, 3);
W3_E = curve_multiply_subspaces(X, curve_V(X, 1), W_E);
R3 = matsmall_coker(rowpermute(W3_E, piv3), p, T);
piv5 = curve_pivots_V(X, 5);
W5_E = curve_multiply_subspaces(X, W2, W3_E);
R5 = matsmall_coker(rowpermute(W5_E, piv5), p, T);
u3 = curve_multiply_sections(X, u, curve_multiply_sections(X, u, u));
tau = norm_of_section(X, u3, C2, piv5, R5);
gamma = cgetg(m + 2, t_VEC);
gel(gamma, 1) = gen_1;
gel(gamma, 2) = gen_1;
for (l = 2; l <= m; l++) {
i = mael(c, l - 1, 1);
j = mael(c, l - 1, 2);
sigma = norm_of_section(X, gel(s, l - 1), C2, piv5, R5);
gel(gamma, l + 1) = gdiv(tau, gmul(sigma, gmul(gel(gamma, i + 1),
gel(gamma, j + 1))));
}
return gmul(gel(gamma, m + 1),
gdiv(norm_of_section(X, v, C2, piv3, R3),
norm_of_section(X, u, C2, piv3, R3)));
}
static GEN
eval_function(GEN J, GEN c, GEN W_D, GEN W_D0, GEN u_D0,
GEN W_E, GEN W_E0) {
GEN D, s, v;
torsion_data(J, W_D, W_D0, c, &D, &s, &v, mkvec2(W_E, W_E0));
return gdiv(eval_half(J, c, u_D0, D, s, v, W_E),
eval_half(J, c, u_D0, D, s, v, W_E0));
}
/*
Compute the Tate-Lichtenbaum-Frey-Rück pairing: let m be a
positive integer not divisible by the characteristic of the
......@@ -224,84 +152,20 @@ torsion_data(GEN J, GEN W_D, GEN W_D0, GEN c,
GEN
jacobian_tate_pairing(GEN J, GEN W_D, GEN W_E, long n) {
GEN q = curve_base_field_cardinality(J);
GEN c, D, W_D0, s, u, v, Iplus, Iminus;
GEN c, u_D0, W_D0, u_E0, W_E0, f_E;
pari_sp av = avma;
if (n <= 0 || smodis(q, n) != 1)
pari_err(e_MISC,
"base field does not contain the roots of unity of order %li",
n);
pari_err(e_MISC, "base field does not contain "
"the roots of unity of order %li", n);
if (jacobian_type(J) != JACOBIAN_TYPE_MEDIUM)
pari_err_IMPL("jacobian_tate_pairing for non-medium models");
c = addflip_chain(stoi(n));
u = gel(curve_V(J, 1), 1);
W_D0 = curve_multiply_section_subspace(J, u, curve_V(J, 1));
torsion_data(J, W_D, W_D0, c, &D, &s, &v);
Iplus = iso(J, c, D, jacobian_zero(J), s, u, v);
Iminus = iso(J, c, D, W_E, s, u, v);
return gerepileupto(av, powgi(gdiv(Iplus, Iminus),
diviuexact(subis(q, 1), n)));
}
static GEN
eval_half(GEN X, GEN c, GEN u, GEN D, GEN s, GEN v, GEN W_E) {
unsigned long p = curve_base_field_characteristic(X);
GEN T = curve_base_field_polynomial(X);
long m = lg(c);
GEN W2, Q2, W3, Q3, W3_E, W3_D, Q3_D;
GEN gamma_0, gamma_1, gamma, delta, M0, M1;
pari_sp av = avma;
W2 = curve_V(X, 2);
Q2 = matsmall_quotient(W2, W_E, p, T);
W3 = curve_V(X, 3);
W3_E = curve_multiply_subspaces(X, curve_V(X, 1), W_E);
Q3 = matsmall_quotient(W3, W3_E, p, T);
quotient_maps(X, D, W_E, &W3_D, &Q3_D);
gamma_0 = norm_of_section(X, u, W2, gel(W3_D, 1),
Q2, gel(Q3_D, 1));
M0 = matsmall_solve_left(gel(Q3_D, 1),
matsmall_mul(Q3, matsmall_solve(W3, gel(W3_D, 1),
p, T),
p, T),
p, T);
M1 = matsmall_solve_left(gel(Q3_D, 2),
matsmall_mul(Q3, matsmall_solve(W3, gel(W3_D, 2),
p, T),
p, T),
p, T);
gamma_1 = gmul(matsmall_det(matsmall_solve(M0, M1, p, T), p, T),
gamma_0);
gamma = compute_gamma(X, D, c, W_E, s, W2, Q2, W3_D, Q3_D,
gamma_0, gamma_1);
delta = norm_of_section(X, v, W2, gel(W3_D, m + 1),
Q2, gel(Q3_D, m + 1));
return gerepileupto(av, ginv(gmul(gel(gamma, m + 1), delta)));
}
static GEN
eval_function(GEN J, GEN c, GEN W_D, GEN W_D0, GEN u_D0,
GEN W_E, GEN W_E0) {
GEN D, s, v;
torsion_data(J, W_D, W_D0, c, &D, &s, &v);
return gdiv(eval_half(J, c, u_D0, D, s, v, W_E),
eval_half(J, c, u_D0, D, s, v, W_E0));
}
static long
divisors_disjoint(GEN J, GEN W_D, GEN W_E) {
unsigned long p = curve_base_field_characteristic(J);
GEN T = curve_base_field_polynomial(J);
GEN W_F;
W_D = curve_multiply_subspaces(J, W_D, curve_V(J, 1));
W_E = curve_multiply_subspaces(J, W_E, curve_V(J, 1));
W_F = matsmall_image(shallowconcat(W_D, W_E), p, T);
return curve_divisor_degree(J, W_F, 3) == 0;
find_disjoint_divisors(J, W_D, &W_E, &u_D0, &W_D0, &u_E0, &W_E0);
f_E = eval_function(J, c, W_D, W_D0, u_D0, W_E, W_E0);