Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
241818 views
1
#include <stdlib.h>
2
#include <stdio.h>
3
#include <math.h>
4
#include "gmp.h"
5
#include "mpzutil.h"
6
#include "ffwrapper.h"
7
#include "ffpoly.h"
8
#include "hecurve.h"
9
#include "jac.h"
10
#include "jacorder.h"
11
#include "smalljac.h"
12
#include "smalljac_g23.h"
13
#include "cstd.h"
14
15
/*
16
Copyright 2007 Andrew V. Sutherland
17
18
This file is part of smalljac.
19
20
smalljac is free software: you can redistribute it and/or modify
21
it under the terms of the GNU General Public License as published by
22
the Free Software Foundation, either version 2 of the License, or
23
(at your option) any later version.
24
25
smalljac is distributed in the hope that it will be useful,
26
but WITHOUT ANY WARRANTY; without even the implied warranty of
27
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28
GNU General Public License for more details.
29
30
You should have received a copy of the GNU General Public License
31
along with smalljac. If not, see <http://www.gnu.org/licenses/>.
32
*/
33
34
/*
35
This module contains genus 2 and genus 3 specific code for deriving the
36
numerator of the zeta function, P(T) = L_p(T), when given certain
37
partial information such as the coefficients mod p or the values P(1) and P(-1).
38
*/
39
40
/*
41
Derive P(T) from P(1) and P(-1) in genus 2. No group operations required. Assumes p < 2^31
42
Sanity check coefficients - caller may not be sure about P(1) and P(-1) and may use this to narrow down the possibilities
43
*/
44
int smalljac_genus2_charpoly (long a[3], long p, double sqrtp, long P1, long PN1)
45
{
46
if ( p > (1L<<31) ) { err_printf ("Overflow in smalljac_genus3_charpoly, p = %ld\n", p); return 0; }
47
a[0] = (P1-PN1)/(2*(p+1));
48
a[1] = ((P1+PN1) - 2*(p*p+1)) / 2;
49
if ( (p*p+1) + (p+1)*a[0] + a[1] != P1 ) return 0;
50
if ( (p*p+1) - (p+1)*a[0] + a[1] != PN1 ) return 0;
51
if ( abs(a[0]) > 4*sqrtp ) return 0; // standard Weil bound
52
if ( a[1] > 2*p + a[0]*a[0]/4 || a[1] < -2*p+a[0]*a[0]/2 ) return 0; // these bounds follow from Prop. 4 of [KedlayaSutherland2007]
53
if ( abs(a[2]) > 20*p*sqrtp ) return 0;
54
return 1;
55
}
56
57
58
/*
59
Derive P(T) from P(1), P(-1) and #C/F_p in genus 3. No group operations required. Assumes p<2^20
60
Sanity check coefficients - caller may not be sure about P(1) and P(-1) and may use this to narrow down the possibilities
61
*/
62
int smalljac_genus3_charpoly (long a[3], long p, double sqrtp, long P1, long PN1, unsigned long pts)
63
{
64
if ( p > (1L<<20) ) { err_printf ("Overflow in smalljac_genus3_charpoly, p = %ld\n", p); return 0; }
65
a[0] = (long)pts - (long)(p+1);
66
a[2] = ((P1-PN1) - 2*(p*p+1)*a[0]) / 2;
67
a[1] = (P1 - (p*p*p+1) - (p*p+1)*a[0] - a[2])/(p+1);
68
if ( (p*p*p+1) + (p*p+1)*a[0] + (p+1)*a[1] + a[2] != P1 ) return 0;
69
if ( (p*p*p+1) - (p*p+1)*a[0] + (p+1)*a[1] - a[2] != PN1 ) return 0;
70
if ( abs(a[0]) > 6*sqrtp ) return 0; // standard Weil bound
71
if ( a[1] > 3*p + a[0]*a[0]/3 || a[1] < -3*p +a[0]*a[0]/2 ) return 0; // these bounds on a2 follow from Prop. 4 of [KedlayaSutherland2007]
72
if ( abs(a[2]) > 20*p*sqrtp ) return 0;
73
return 1;
74
}
75
76
77
/*
78
Derive P(T) from P(1) in genus 2, using O(\lg(p)) gops in the twist.
79
*/
80
81
int smalljac_genus2_charpoly_from_P1 (long a[2], long P1, long Min, long Max, curve_t c[1])
82
{
83
curve_t twist;
84
jac_t h, g;
85
unsigned long n;
86
long e, o, to, to0, a0, p;
87
int i,k;
88
89
n = jac_gops;
90
ff_poly_twist (twist.f, c[0].f, c[0].d);
91
twist.d = 5;
92
93
// We want to compute a and b such that P(T) = 1 + a1T + a2T^2 + pa1T^3 + p^2T^4
94
// We are given P(1) and we know that P(-1) is the order of the twist
95
// We also know that a1 >= (P(1) - (p^2+1) - 6p)/(p+1) and a <= (P(1) - (p^2+1) + 6p)/(p+1)
96
// which gives a range of at most 12 values for a1, and thus at most 12 possibilities for P(-1) = P(1) - 2(p+1)a1
97
// all of which differ by a multiple of 2(p+1). We just need to distinguish P(-1) among these 11 possibilities.
98
p = _ff_p;
99
a0 = (P1 - p*p + 6*p - 1)/(p+1); // max value for a1 = (P(1) - (p^2+6p+1)) / (p+1) gives min value for twist order to
100
to = P1 - 2*(p+1)*a0;
101
to0 = to;
102
i = 0;
103
while ( to < Min ) { i++; to += 2*(p+1); } // Skip twist orders not in Weil interval
104
for ( k = 0 ; k < SMALLJAC_RETRIES ; k++ ) {
105
_jac_random(g, twist);
106
jac_exp_ui (&h, &g, 2*(p+1), &twist);
107
if ( ! _jac_is_identity(h) ) break;
108
}
109
if ( k == SMALLJAC_RETRIES ) {
110
// 2*(p+1) is an exponent for the group - hopefully only one candidate twist order is compatible, since they are all exponents
111
o = 0;
112
for ( ; i <= 12 ; i++, to += 2*(p+1) ) {
113
if ( to > Max ) break;
114
if ( ui_compatible (to, 2*(p+1)) ) {
115
if ( o ) { /*err_printf ("%7u: More than one twist order implied by P(1) = %ld is a 2(p+1) compatible exponent of the twist (%ld,%ld).\n", _ff_p, P1, o, to);*/ return 0; }
116
o = to;
117
}
118
}
119
} else {
120
// Ok we have an element whose order contains a prime not in 2*(p+1). This should almost always uniquely determine the twist
121
// since two candidate twist orders differ by i*2*(p+1) where i <= 10
122
o = 0;
123
jac_exp_ui (&g, &g, to, &twist);
124
for ( ; i <= 12 ; i++, to += 2*(p+1) ) {
125
if ( to > Max ) break;
126
if ( _jac_is_identity (g) ) {
127
if ( o ) { // we know that e=(to-o) is an exponent of g - try to find an element for which e is not an exponent
128
e = to-o;
129
for ( k = 0 ; k < SMALLJAC_RETRIES ; k++ ) {
130
_jac_random(g, twist);
131
jac_exp_ui (&h, &g, e, &twist);
132
if ( ! _jac_is_identity(h) ) break;
133
}
134
if ( k == SMALLJAC_RETRIES ) {/*err_printf ("%7u: More than one twist order implied by P(1) = %ld is an exponent of the twist (%ld,%ld).\n", _ff_p, P1, o, to);*/ return 0; }
135
jac_exp_ui (&h, &g, o, &twist);
136
if ( _jac_is_identity(h) ) {
137
// to can't be an exponent, and o is probably the twist order, reset g and h to continue the search
138
jac_exp_ui (&h, &g, 2*(p+1), &twist);
139
jac_exp_ui (&g, &g, to, &twist);
140
} else {
141
o = 0;
142
jac_exp_ui (&h, &g, 2*(p+1), &twist);
143
jac_exp_ui (&g, &g, to, &twist);
144
if ( _jac_is_identity (g) ) o = to;
145
}
146
} else {
147
o = to;
148
}
149
}
150
_jac_mult (g, g, h, twist);
151
}
152
}
153
if ( ! o ) { err_printf ("%7u: None of the implied twist orders for P(1) = %ld are exponents with to0 = %ld in Weil interval [%ld,%ld]\n", _ff_p, P1, to0, Min, Max); return 0; }
154
a[0] = (P1 - o) / (2*(p+1)); // a1 = P(1)-P(-1)/(2(p+1))
155
a[1] = (P1+o-2*(p*p+1))/2; // a2 = (P(1)+P(-1) - 2(p^2+1))/2
156
smalljac_charpoly_gops += jac_gops-n;
157
return 1;
158
}
159
160
161
/*
162
Derive P(T) from P(1) in genus 3, using O(p^{1/4}) gops in the twist.
163
*/
164
165
int smalljac_genus3_charpoly_from_P1 (long o[3], long P1, long pts, long Min, long Max, curve_t c[1])
166
{
167
static int init;
168
static mpz_t Tmin, Tmax, e[2];
169
curve_t twist;
170
jac_t g;
171
long p, tmin, tmax, to, spc, bmin, bmax, k;
172
unsigned long n, e0;
173
double x;
174
int constraints[2];
175
int i, cnt;
176
177
n = jac_gops;
178
if ( ! init ) { mpz_init (Tmin); mpz_init (Tmax); mpz_init (e[0]); mpz_init (e[1]); init = 1; }
179
180
ff_poly_twist (twist.f, c[0].f, c[0].d);
181
twist.d = c[0].d;
182
183
p = (long) _ff_p;
184
o[0] = pts - 1 - p;
185
x = sqrt((double)p);
186
spc = (long)ceil(x);
187
bmin = (P1 - (p*p*p+1) - (p*p+1)*o[0] - 20*p*spc) / (p+1);
188
tmin = 2*(p*p*p+1) - P1+ 2*(p+1)*bmin;
189
bmax = (P1 - (p*p*p+1) - (p*p+1)*o[0] + 20*p*spc) / (p+1) + 1;
190
tmax = 2*(p*p*p+1) - P1+ 2*(p+1)*bmax;
191
if ( tmin < Min ) tmin += _ui_ceil_ratio((Min-tmin),2*(p+1)) * 2*(p+1);
192
tmax = 2*(p*p*p+1) - P1+ 2*(p+1)*15*p;
193
if ( tmax > Max ) tmax -= (tmax-Max)/(2*(p+1)) * 2*(p+1);
194
_jac_random (g,twist);
195
mpz_set_ui (Tmin, tmin); mpz_set_ui (Tmax, tmax);
196
cnt = jac_search (e, &g, 2*(p+1), Tmin, Tmax, &twist);
197
if ( ! cnt ) { err_printf ("%7u: Search failed in genus3_charpoly with P(1) = %ld in [%ld,%ld]\n", _ff_p, P1, Min, Max); return 0; }
198
if ( cnt > 1 ) {
199
k = 2*(p*p*p+1) - P1; // note k may be big
200
constraints[0] = ( k < 0 ? (int) (2*(p+1) - ((-k)%(2*(p+1)))) : (int) (k%(2*(p+1))) );
201
constraints[1] = -1;
202
if ( jac_order (&to, Min, Max, -o[0], constraints, &twist, 0) != 1 ) {
203
err_printf ("%7u: Ambiguous result in genus3_charpoly with P(1) = %ld in [%ld,%ld] (%ld,%ld), order computation for twist failed\n", _ff_p, P1, Min, Max, e[0], e[1]);
204
return 0;
205
}
206
} else {
207
e0 = mpz_get_ui (e[0]);
208
to = _ui_ceil_ratio(tmin,e0)*e0;
209
}
210
211
if ( ! smalljac_genus3_charpoly (o, p, x, P1, to, pts) ) { err_printf ("%7u: Unable to derive consistent Lpolynomial from P(1) = %lu and P(-1) = %lu given a1 = %ld\n", p, P1, to, o[0]); return 0; }
212
smalljac_charpoly_gops += jac_gops-n;
213
return 1;
214
}
215
216
/*
217
Derive P(T) given P(T) mod p in genus 2, using O(lg(p)) group operations.
218
*/
219
int smalljac_genus2_charpoly_from_Pmodp (long a[2], curve_t c[1])
220
{
221
jac_t g, h;
222
unsigned long n;
223
long p, e0, e1, N, Min, Max;
224
225
p = (long) _ff_p;
226
227
n = jac_gops;
228
if ( a[1] < 0 ) a[1] += p;
229
Min = (p*p+1) + (p+1)*a[0] - 2*p;
230
Max = (p*p+1) + (p+1)*a[0] + 6*p;
231
N = ((p*p+1)+(p+1)*a[0] + a[1]) % p; // N = P(1) mod p
232
Min = p*(Min/p) + N; // congruent to P(1) mod p
233
e0 = Min;
234
_jac_random(g, c[0]);
235
jac_exp_ui (&h, &g, e0, c);
236
jac_exp_ui (&g, &g, p, c);
237
e1 = 0;
238
while ( e0 <= Max ) {
239
if ( _jac_is_identity (h) ) {
240
if ( e1 ) { err_printf ("%lu: Ambiguous result in genus2_charpoly_from_Pmodp %lu and %lu possible exponents\n", p, e1, e0); return 0; }
241
e1 = e0;
242
}
243
_jac_mult (h, h, g, c[0]);
244
e0 += p;
245
}
246
if ( ! e1 ) { err_printf ("%9u: Search failed in genus2_charpoly_from_Pmodp, a[1] = %ld, Min = %ld, Max = %ld\n", _ff_p, a[1], Min, Max); return 0; }
247
a[1] = e1 - (p*p+1) - (p+1)*a[0];
248
smalljac_charpoly_gops += jac_gops-n;
249
return 1;
250
}
251
252
/*
253
Derive P(T) given P(T) mod p in genus 3, using O(p^{1/4}) group operations.
254
255
We assume p is big enough to avoid any unpleasant special cases but less than 2^31
256
*/
257
int smalljac_genus3_charpoly_from_Pmodp (long a[3], curve_t c[1])
258
{
259
static int init;
260
static mpz_t Min, Max, e[2], z, O;
261
jac_t g;
262
long p, M, N, T, a2, a2Min, a2Max, good_a2, spc;
263
unsigned long n;
264
double x;
265
int i, cnt;
266
267
if ( ! init ) { mpz_init (Min); mpz_init (Max); mpz_init (e[0]); mpz_init (e[1]); mpz_init (z); mpz_init (O); init = 1; }
268
269
p = (long) _ff_p;
270
x = sqrt((double)p);
271
spc = (long)ceil(x);
272
273
cnt = 0;
274
n = jac_gops;
275
if ( a[1] < 0 ) a[1] += p;
276
// Set a2 bounds based on Proposition 4 of KedlayaSutherland 2007
277
a2Min = -p+a[1];
278
a2Max = 3*p + _ui_ceil_ratio(a[0]*a[0], 3);
279
for ( a2 = a2Min ; a2 <= a2Max ; a2 += p ) {
280
mpz_set_ui (Min, p*p); mpz_mul_ui (Min, Min, p); mpz_add_ui (Min, Min, 1);
281
mpz_set_i (z, a[0]); mpz_mul_ui (z, z, p*p+1); mpz_add (Min, Min, z);
282
mpz_set_i (z, a2); mpz_mul_ui (z, z, p+1); mpz_add (Min, Min, z);
283
mpz_set_i (e[0], a[2]);
284
mpz_add (z, Min, e[0]);
285
mpz_mod_ui (z, z, p);
286
N = mpz_get_ui (z); // N is P(1)=p^3+1 + (p^2+1)a1 + (p+1)a2 +a3 mod p
287
mpz_add_ui (Max, Min, 20*p*spc);
288
mpz_sub_ui (Min, Min, 20*p*spc);
289
mpz_tdiv_q_ui (Min, Min, p);
290
mpz_mul_ui (Min, Min, p);
291
mpz_add_ui (Min, Min, N);
292
_jac_random (g, c[0]);
293
i = jac_search (e, &g, p, Min, Max, c);
294
if ( ! cnt && i ) { mpz_set(O,e[0]); good_a2 = a2; }
295
cnt += i;
296
if ( cnt > 1 ) {
297
err_printf ("%lu: Ambiguous result in genus3_charpoly_from_Pmodp %Zd and %Zd possible exponents (i=%d)\n", _ff_p, O, (i>1?e[1]:e[0]),i);
298
return 0;
299
}
300
}
301
if ( cnt != 1 ) {
302
err_printf ("%9u: Search failed in genus3_charpoly_from_Pmodp a2Min = %ld, a2Max = %ld, Min = %Zd, Max = %Zd\n", _ff_p, a2Min, a2Max, Min, Max);
303
err_printf ("%9u: padic_lpoly coefficients: a1=%ld, a2=%ld, a3=%ld\n", _ff_p, a[0], a[1], a[2]);
304
return 0;
305
}
306
a[1] = good_a2;
307
mpz_set_ui (z, p*p); mpz_mul_ui (z, z, p); mpz_add_ui (z, z, 1);
308
mpz_sub (O, O, z);
309
mpz_set_i (z, a[0]); mpz_mul_ui (z, z, p*p+1);
310
mpz_sub (O, O, z);
311
mpz_set_i (z, a[1]); mpz_mul_ui (z, z, p+1);
312
mpz_sub (O, O, z);
313
a[2] = mpz_get_i (O);
314
smalljac_charpoly_gops += jac_gops-n;
315
return 1;
316
}
317
318