Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
241818 views
1
#include <stdlib.h>
2
#include <stdio.h>
3
#include <stdint.h>
4
#include <math.h>
5
#include "gmp.h"
6
#include "mpzutil.h"
7
#include "jac.h"
8
#include "hecurve.h"
9
#include "ff.h"
10
#include "smalljactab.h"
11
#include "cstd.h"
12
13
/*
14
Copyright 2007 Andrew V. Sutherland
15
16
This file is part of smalljac.
17
18
smalljac is free software: you can redistribute it and/or modify
19
it under the terms of the GNU General Public License as published by
20
the Free Software Foundation, either version 2 of the License, or
21
(at your option) any later version.
22
23
smalljac is distributed in the hope that it will be useful,
24
but WITHOUT ANY WARRANTY; without even the implied warranty of
25
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
GNU General Public License for more details.
27
28
You should have received a copy of the GNU General Public License
29
along with smalljac. If not, see <http://www.gnu.org/licenses/>.
30
*/
31
32
/*
33
As used by smalljac, the CONFIDENCE parameter does not affect the correctness of the output - smalljac
34
always proves its results unconditionally. Setting CONFIDENCE too low could cause smalljac to fail, however.
35
*/
36
37
#define CONFIDENCE 40 // must be less than 64 - set a bit high because we don't trust the uniformity of random elements in genus 3
38
39
int jac_vector_logarithm (unsigned long e[], jac_t a[], unsigned long ords[], int k, jac_t b[1], curve_t c[1]);
40
41
/*
42
Given the order (or multiple of the exponent) of the group, N = #J(C/F_q), jac_structure computes the abelian group structure of J(C/F_q)
43
as a product of cylclic groups Z_m[0] x ... x Z_m[n-1] with m[0] | m[1] | ... | m[n-1] and returns n. The flag fExponent, when set, indicates that N is only
44
guaranteed to be a multiple of the group exponent, not necessarily its order.
45
46
Generators are not computed, but they easily could be (at a slight increase in cost).
47
*/
48
int jac_structure (long m[], curve_t c[1], unsigned long N, int fExponent)
49
{
50
unsigned long h[JAC_MAX_FACTORS];
51
unsigned long p[JAC_MAX_FACTORS];
52
unsigned long t[JAC_MAX_GENERATORS];
53
unsigned long ords[JAC_MAX_GENERATORS];
54
jac_t x[1], a[JAC_MAX_GENERATORS];
55
register int i, j, k, n, r, w, maxj;
56
register unsigned long max, q, M;
57
58
w = ui_factor (p, h, N);
59
if ( ! w ) { err_printf ("ui_factor_small failed"); exit (0); }
60
n = 1;
61
for ( i = 0 ; i < c->d-1 ; i++ ) t[i] = 1;
62
// could add code here to optimize rank 1 2-Sylow subgroups by counting the factors of f(x)
63
for ( i = 0 ; i < w ; i++ ) {
64
if ( ! fExponent ) {
65
// The optimizations below rely on N being the group order
66
if ( h[i] == 1 ) { t[0] *= p[i]; continue; }
67
for ( q = p[i]*p[i], j = 2 ; j < h[i] ; j++ ) q *= p[i];
68
// Todo: Add genus 1 check for divisibility of _ff_p-1
69
// Before performing a p-Sylow subgroup computation, expend some effort trying to
70
// prove the p-Sylow subgroup is cyclic - we expect this to often be the case and
71
// it only requires O(lg(N)) gops.
72
M = N/p[i]; // was N/q which can't be right
73
for ( j = 0 ; j < JAC_CYCLIC_TESTS ; j++ ) {
74
_jac_random (x[0], c[0]);
75
jac_exp_ui (x, x, M, c);
76
if ( ! _jac_is_identity (x[0]) ) break;
77
}
78
if ( j < JAC_CYCLIC_TESTS ) { for ( j = 0 ; j < h[i] ; j++ ) t[0] *= p[i]; continue; }
79
} else {
80
q = 0;
81
}
82
r = jac_sylow (a, ords, p[i], N, q, 0, c);
83
if ( r <= 0 ) { err_printf ("%lu-Sylow computation failed\n", p[i]); exit (0); }
84
for ( j = 1, M = ords[0] ; j < r ; j++ ) M *= ords[j];
85
if ( q && M != q ) {
86
err_printf ("jac_sylow computed subgroup of rank %d, size %lu when size %lu was expected (N=%ld)\n", r, M, q, N);
87
printf ("p=%ld: ", _ff_p); _curve_print (c[0]);
88
exit (0);
89
}
90
// pull p-Sylow factors out in decreasing order by size (largest first). Don't bother sorting, there can only be a few
91
if ( n < r ) n = r;
92
for ( j = 0 ; j < r ; j++ ) {
93
for ( max = 0, k = 0 ; k < r ; k++ ) if ( ords[k] > max ) { max = ords[k]; maxj = k; }
94
t[j] *= max;
95
ords[maxj] = 0;
96
}
97
}
98
// sanity checks - can be removed eventually
99
if ( n > c->d-1 ) { err_printf ("jac_structure failed - computed rank %d > 2g = %d\n", n, c->d-1); exit (0); }
100
if ( ! fExponent ) {
101
for ( M = 1, i = 0 ; i < n ; i++ ) M *= t[i];
102
if ( M != N ) { err_printf ("jac_structure failed - computed order %lu not equal to given order %lu\n", M, N); exit (0); }
103
}
104
for ( i = 0 ; i < n-1 ; i++ ) if ( t[i]%t[i+1] ) { err_printf ("jac_structure failed, cyclic order divisibility test failed t[i] = %lu, t[i+1] = %lu\n", t[i], t[i+1]); exit (0); }
105
// copy results into output array, reversing order to put smallest first
106
for ( i = 0 ; i < n ; i++ ) m[i] = t[n-i-1];
107
return n;
108
}
109
110
111
/*
112
jac_sylow computes the p-Sylow subgroup of the jacobian using a provided exponent E (E can be any multiple of the group exponent)
113
M is an upper bound on the maximum size of the p-Sylow subgroup - if this value is too small, jac_sylow will compute a
114
subgroup which may not be the full p-Sylow subgroup. It is assumed that the order of the p-Sylow subgroup fits in an unsigned long.
115
116
The optional parameter limit will force jac_sylow to terminate with an error if the p-Sylow subgroup is found to be larger than limit.
117
This is used to ensure an O(|G|^{1/4}) running time. See Proposition 2 of [KedlayaSutherland2007].
118
119
The computed subgroup is in the form of a basis a[] with the order of each basis element in ords[]. The size of the basis
120
(the p-rank of the Jacobian) is returned. If maxgops is exceeded, -1 is returned.
121
122
This algorithm is an impelmentation of Algorithm 9.1 (including Algorithm 9.2) of [SutherlandThesis], specialized to a single Sylow subgroup.
123
*/
124
125
int jac_sylow (jac_t a[JAC_MAX_GENERATORS], unsigned long ords[JAC_MAX_GENERATORS], unsigned p, unsigned long E, unsigned long M, unsigned long limit, curve_t c[1])
126
{
127
jac_t b;
128
unsigned long h;
129
unsigned long e[JAC_MAX_GENERATORS];
130
unsigned long m, q, x, order;
131
int k, n, cnt, retries, min, d, temp;
132
int sts;
133
134
for ( h = 0 ; ! (E%p) ; h++ ) E/= p;
135
if ( ! h ) { err_printf ("Trivial call to smalljac_sylow E = %lu, p = %u\n", E, p); return 0; }
136
k = 0;
137
order = 1;
138
// Get initial generator
139
for ( cnt = 0 ; cnt < CONFIDENCE ; cnt++ ) {
140
_jac_random (a[k], c[0]);
141
jac_exp_ui (a+k, a+k, E, c);
142
_jac_set (b, a[k]);
143
ords[k] = jac_pp_order_ui (&b, p, h, c);
144
if ( ords[k] > 1 ) break;
145
}
146
if ( ords[k] < 2 ) { err_printf ("smalljac_sylow couldn't find any generators for %d-Sylow subgroup - bad exponent %ld?!\n", p, E); exit (0); }
147
dbg_printf ("First generator for %d-sylow subgroup has order %d, E = %ld, M = %ld, limit = %ld\n", p, ords[k], E, M, limit);
148
k++;
149
// adjust retries based on p to achieve probabilty > 2^confidence
150
for ( retries = 1, x = p ; x < (1UL<<CONFIDENCE) ; x *= p, retries++ );
151
for ( cnt = 0 ; cnt < retries ; ) {
152
for ( n = 0, x = 1 ; n < k ; x *= ords[n], n++ );
153
// if we have exceeded the limit, return an error
154
if ( limit && x > limit ){ dbg_printf ("Sylow subgroup computation terminated unsuccessfully due to %ld*%ld > %ld\n", p, x, limit); return -1; }
155
// if adding another basis element would make group size > M then we must be done
156
if ( M && p*x > M ) { dbg_printf ("Sylow subgroup computation successfully terminated due to bound M = %ld\n", M); break; }
157
_jac_random (a[k], c[0]);
158
jac_exp_ui (a+k, a+k, E, c);
159
repeat:
160
if ( _jac_is_identity (a[k]) ) continue;
161
_jac_set (b, a[k]);
162
_jac_invert (b);
163
sts = jac_vector_logarithm (e, a, ords, k, &b, c);
164
if ( sts > 0 ) { cnt++; continue; }
165
if ( sts < 0 ) return -1;
166
// if an unspanned element forces us past limit, return error
167
if ( limit && p*x > limit ){ dbg_printf ("Sylow subgroup computation terminated unsuccessfully due to %ld*%ld > %ld\n", p, x, limit); return -1; }
168
ords[k] = jac_pp_order_ui (&b, p, h, c);
169
if ( ords[k] < 2 ) { err_printf ("unexpected order %d returned from jac_pp_order_ui", ords[k]); exit (0); }
170
dbg_printf ("Found unspanned element with order %d\n", ords[k]);
171
for ( m = p ; m < ords[k] ; m *= p ) {
172
jac_exp_ui (&b, &b, p, c);
173
sts = jac_vector_logarithm (e, a, ords, k, &b, c);
174
if ( sts > 0 ) break;
175
if ( sts < 0 ) return -1;
176
}
177
if ( m < ords[k] ) {
178
for ( n = 0 ; n < k ; n++ ) {
179
if ( e[n] ) {
180
q = ui_pp_div (e[n], p);
181
if ( q != e[n] ) {
182
jac_exp_ui (a+n, a+n, e[n]/q, c);
183
e[n] = q;
184
}
185
}
186
}
187
min = -1; d = m;
188
for ( n = 0 ; n < k ; n++ )
189
if ( e[n] && e[n] < d ) { min = n; d = e[n]; }
190
dbg_printf ("min = %d, d = %d\n", min, d);
191
if ( min == -1 ) {
192
for ( n = 0 ; n < k ; n++ ) {
193
if ( e[n] != 0 ) {
194
if ( (e[n]%m) != 0 ) { out_printf ("Problem, %d not divisible by %d\n", e[n], m); exit (1); }
195
jac_exp_ui (&b, a+n, e[n]/m, c);
196
_jac_mult (a[k], a[k], b, c[0]);
197
}
198
}
199
ords[k] = m;
200
temp = jac_pp_order_ui (a+k, p, h, c);
201
if ( temp != ords[k] ) { err_printf ("%lu: Order mismatch 1, %d != %d for element ", _ff_p, temp, ords[k]); _jac_print(a[k]); exit (0); }
202
dbg_printf ("Added adjusted generator using relation min == -1.\n");
203
k++;
204
} else {
205
if ( d == 1 ) {
206
dbg_printf ("Removed generator with exponent 1, recomputing relation...\n", e[n], m);
207
n = min;
208
while ( n < k ) {
209
ords[n] = ords[n+1];
210
_jac_set (a[n], a[n+1]);
211
temp = jac_pp_order_ui (a+n, p, h, c);
212
if ( temp != ords[n] ) { err_printf ("Order mismatch 2, %d != %d for element ", temp, ords[n]); _jac_print(a[n]); exit (0); }
213
n++;
214
}
215
k--;
216
if ( ! k) {
217
dbg_printf ("no more generators left, independent element is new generator\n");
218
k++;
219
} else {
220
dbg_printf ("repeating with k = %d\n", k);
221
goto repeat;
222
}
223
} else {
224
if ( (m%e[min]) != 0 ) { out_printf ("Problem, %d not divisible by %d\n", e[min], m); exit (1); }
225
jac_exp_ui (&b, a+k, m/e[min], c);
226
_jac_mult (a[min], a[min], b, c[0]);
227
for ( n = 0 ; n < k ; n++ ) {
228
if ( n != min && e[n] ) {
229
if ( (e[n]%e[min]) != 0 ) { out_printf ("Problem, %d not divisible by %d\n", e[min], m); exit (1); }
230
jac_exp_ui (&b, a+n, e[n]/e[min], c);
231
_jac_mult (a[min], a[min], b, c[0]);
232
}
233
}
234
dbg_printf ("Adjusted existing generator using relation, changed order from %d to %d.\n", ords[min], e[min]);
235
ords[min] = e[min];
236
temp = jac_pp_order_ui (a+min, p, h, c);
237
if ( temp != ords[min] ) { err_printf ("Order mismatch 3, %d != %d for element ", temp, ords[min]); _jac_print(a[min]); exit (0); }
238
goto repeat;
239
}
240
}
241
} else {
242
dbg_printf ("Added new independent generator %d with order %d\n", k, ords[k]);
243
k++;
244
}
245
//printf ("%d generators: \n", k);
246
//for ( n = 0 ; n < k ; n++ ) _jac_print(a[n]); printf (" order %d\n", ords[n]);
247
}
248
return k;
249
}
250
251
252
/*
253
jac_vector_logarithm implements Algorithm 9.3 of [SutherlandThesis]. It is assumed the order of the group
254
spanned by the provided basis (i.e. the product of the ords[i]) fits in a long.
255
256
This algorithm is a straight copy of the generic version and does not include any optimizations for fast inverses
257
or parallel group operations. smalljac uses this very infrequently, so we don't bother optimizing it.
258
*/
259
260
int jac_vector_logarithm (unsigned long e[], jac_t a[], unsigned long ords[], int k, jac_t beta[1], curve_t curve[1])
261
{
262
static int stashsize;
263
static jac_t *stash;
264
jac_t g, h, ht, betainverse;
265
unsigned long E;
266
register long i, b, c, ct, d, u, s, t, j, l;
267
uint32_t matches[SMALLJAC_MAX_MATCHES];
268
long m, n;
269
int sts, bits, found;
270
271
if ( _jac_is_identity (beta[0]) ) { for ( i = 0 ; i < k ; i++ ) e[i] = 0; return 1; }
272
if ( k == 0 ) { err_printf ("Invalid k value in grp_vector_logarithm"); exit (0); }
273
274
sts = 0;
275
276
// quick sanity check
277
for ( i = 0 ; i < k ; i++ ) if ( ords[i] < 2 ) { out_printf ("Invalid order %d specified in grp_vector_logarithm", ords[i]); exit (0); }
278
279
//out_printf ("Vector logarithm searching for "); _jac_print (beta[0]);
280
//for ( i = 0 ; i < k ; i++ ) { out_printf ("(%d) ",ords[i]); _jac_print (a[i]); }
281
282
for ( E = ords[0], i = 1 ; i < k ; i++ ) E *= ords[i];
283
//out_printf ("E = %lu\n", E);
284
285
c = (long) floor(sqrt(E));
286
b = 1;
287
for ( d = 0 ; d < k ; d++ ) {
288
if ( b*ords[d] > c ) break; // overflow could happen here if the product of ords[d] doesn't fit in a long
289
b *= ords[d];
290
}
291
c /= b;
292
l = b;
293
b *= c;
294
295
// Note that we will be giant stepping via alpha[d]^c
296
297
// initialize table and init/expand stash if needed
298
for ( bits = 10, i = (1<<10) ; i < 2*b ; i <<= 1, bits++ ); // aim for a load factor of 0.5
299
smalljac_table_init (bits);
300
if ( b >= stashsize ) {
301
if ( stash ) {
302
for ( stashsize *= 2 ; stashsize < b ; stashsize *= 2 );
303
stashsize *= 2; stash = (jac_t *) realloc (stash, stashsize*sizeof(*stash));
304
} else {
305
for ( stashsize = 1024 ; stashsize < b ; stashsize *= 2 );
306
stash = (jac_t *) malloc (stashsize*sizeof(*stash));
307
}
308
}
309
310
_jac_set_identity (g);
311
// baby steps - we currently don't bother trying to do these in parallel
312
for ( i = 1 ; i < b ; i++ ) {
313
_jac_mult (g, g, a[0], curve[0]);
314
for ( j = 0, m = ords[0] ; (i%m) == 0 ; m *= ords[++j] ) _jac_mult (g, g, a[j+1], curve[0]);
315
if ( _jac_cmp (g, beta[0]) == 1 ) break;
316
smalljac_table_insert (&g, i);
317
_jac_set (stash[i], g);
318
}
319
if ( _jac_cmp (g, beta[0]) == 1 ) {
320
for ( j = 0 ; j < k ; j++ ) {
321
e[j] = i%ords[j];
322
i /= ords[j];
323
}
324
sts = 1;
325
goto finish;
326
}
327
// giant steps - step counter is combination of t for the kth digit and u for the higher digits
328
_jac_set (betainverse, beta[0]);
329
_jac_invert (betainverse);
330
_jac_set (g, betainverse);
331
jac_exp_ui (&h, a+d, c, curve);
332
// Setup ht to make top step as we cycle on the center digit
333
if ( c > 1 ) {
334
ct = ords[d]-1 - c*((ords[d]-1)/c);
335
jac_exp_ui (&ht, a+d, ct, curve);
336
} else {
337
_jac_set_identity (ht);
338
}
339
found = 0;
340
for ( s = 1, t = 0, u = 0 ; ! found ; s++ ) {
341
// Need to hit top of the center digit every time as we cycle through
342
if ( t < ords[d]-1 && t+c >= ords[d] ) {
343
_jac_mult (g, g, ht, curve[0]);
344
t += ct;
345
if ( t != ords[d]-1 ) { err_printf ("ct=%d invalid t = %d, c=%d, ords[d] = %d - didn't hit ords[d]-1 on center digit!", ct, t, c, ords[d]); exit (0); }
346
} else if ( t == ords[d]-1 ) {
347
// carry
348
_jac_mult (g, g, a[d], curve[0]);
349
if ( d == k-1 ) goto done;
350
t = 0; // Note, must set t to 0 here, not reduce mod c
351
_jac_mult (g, g, a[d+1], curve[0]);
352
u++;
353
// propogate carry as required
354
for ( j = d+1, m = ords[d+1] ; (u%m) == 0 ; m *= ords[++j] ) {
355
if ( j == k-1 ) goto done;
356
_jac_mult (g, g, a[j+1], curve[0]);
357
}
358
} else {
359
t += c;
360
_jac_mult (g, g, h, curve[0]);
361
}
362
if ( _jac_is_identity (g) ) {
363
m = 0;
364
found = 1;
365
} else {
366
n = smalljac_table_lookup (matches, &g);
367
for ( i = 0 ; i < n ; i++ ) if ( _jac_cmp(stash[matches[i]], g) == 1 ) break;
368
if ( i < n ) { found = 1; m = matches[i]; } else found = 0;
369
}
370
}
371
done:
372
// If not found take one final step to the top
373
if ( ! found ) {
374
_jac_set (h, a[0]);
375
for ( i = 1 ; i < k ; i++ ) {
376
_jac_mult (h, h, a[i], curve[0]);
377
}
378
_jac_invert (h);
379
_jac_mult (g, h, betainverse, curve[0]);
380
n = smalljac_table_lookup (matches, &g);
381
for ( i = 0 ; i < n ; i++ ) if ( _jac_cmp(stash[matches[i]], g) == 1 ) break;
382
if ( i < n ) { found = 1; m = matches[i]; } else found = 0;
383
if ( ! found && ! _jac_is_identity (g) ) goto finish;
384
for ( i = 0 ; i < k ; i++ ) {
385
e[i] = (ords[i] - 1 - (m%ords[i])) % ords[i];
386
m /= ords[i];
387
}
388
} else {
389
j = m%l;
390
for ( i = 0 ; i < d ; i++ ) {
391
e[i] = (ords[i] - (j%ords[i])) % ords[i];
392
j /= ords[i];
393
}
394
m /= l;
395
if ( m <= t ) e[d] = t-m; else e[d] = ords[d]+t-m;
396
for ( i = d+1 ; i < k ; i++ ) {
397
e[i] = u%ords[i];
398
u /= ords[i];
399
}
400
}
401
sts = 1;
402
finish:
403
404
// verification code - comment this out eventually
405
if ( sts ) {
406
//out_printf ("Vector logarithm found (k=%d) ", k); _jac_print (beta[0]);
407
_jac_set_identity (g);
408
for ( i = 0 ; i < k ; i++ ) {
409
jac_exp_ui (&h, a+i, e[i], curve);
410
_jac_mult (g, g, h, curve[0]);
411
//out_printf ("%d* ", e[i]); _jac_print(a[i]);
412
if ( e[i] == ords[i] ) { puts ("Unreduced exponent!"); exit (1); }
413
}
414
//puts ("");
415
if ( ! _jac_cmp (beta[0], g) == 1 ) { err_printf ("Vector Logarithm invalid - orders suspect!\n"); _jac_print(beta[0]); _jac_print(g); sts = -1; }
416
} else {
417
//out_printf ("Vector logarithm failed to find "); _jac_print(beta[0]);
418
}
419
420
return sts;
421
}
422
423