#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <stdint.h>
#include <memory.h>
#include <math.h>
#include "gmp.h"
#include "mpzutil.h"
#include "ffwrapper.h"
#include "ffpoly.h"
#include "hecurve.h"
#include "jac.h"
#include "smalljac.h"
#include "smalljactab.h"
#include "jacorder.h"
#include "cstd.h"
#if HECURVE_GENUS == 1
unsigned long SMALLJAC_M = 4;
#else
unsigned long SMALLJAC_M = 32;
#endif
#define SMALLJAC_BABY_STASHSIZE 4096
jac_t baby_stash[SMALLJAC_BABY_STASHSIZE];
struct a2tab_entry g2a2tab[] = {
{ -4.00, 5.36, 0.09 },
{ -3.60, 4.72, 0.15 },
{ -3.20, 4.08, 0.17 },
{ -2.80, 3.44, 0.19 },
{ -2.40, 2.80, 0.22 },
{ -2.00, 2.24, 0.29 },
{ -1.60, 1.68, 0.38 },
{ -1.20, 1.20, 0.49 },
{ -0.80, 0.80, 0.62 },
{ -0.40, 0.48, 0.74 },
{ 0.00, 0.48, 0.74 },
{ 0.40, 0.80, 0.62 },
{ 0.80, 1.20, 0.49 },
{ 1.20, 1.68, 0.38 },
{ 1.60, 2.24, 0.29 },
{ 2.00, 2.80, 0.22 },
{ 2.40, 3.44, 0.19 },
{ 2.80, 4.08, 0.17 },
{ 3.20, 4.72, 0.15 },
{ 3.60, 5.36, 0.09 },
{ 4.00, 0.00 , 0.00 }
};
struct a2tab_entry g3a2tab[] = {
{ -6.00, 12.92, 0.15 },
{ -5.40, 10.84, 0.26 },
{ -4.80, 8.92, 0.34 },
{ -4.20, 7.16, 0.40 },
{ -3.60, 5.56, 0.45 },
{ -3.00, 4.12, 0.52 },
{ -2.40, 2.84, 0.61 },
{ -1.80, 1.72, 0.66 },
{ -1.20, 0.92, 0.61 },
{ -0.60, 0.60, 0.55 },
{ 0.00, 0.60, 0.55 },
{ 0.60, 0.92, 0.61 },
{ 1.20, 1.72, 0.66 },
{ 1.80, 2.84, 0.61 },
{ 2.40, 4.12, 0.52 },
{ 3.00, 5.56, 0.45 },
{ 3.60, 7.16, 0.40 },
{ 4.20, 8.92, 0.34 },
{ 4.80, 10.84, 0.26 },
{ 5.40, 12.92, 0.15 },
{ 6.00, 0.00 , 0.00 }
};
unsigned long jac_curve_count, jac_prebaby_gops, jac_baby_gops, jac_pregiant_gops, jac_giant_gops, jac_fastorder_gops, jac_ambexp_gops, jac_exp_gops, jac_charpoly_gops, jac_order_count;
int jac_order (unsigned long *pP1, unsigned long Min, unsigned long Max, long a1, int *constraints, curve_t c[1], int fExponentOnly)
{
static mpz_t Z;
static int init;
jac_t g, gen[JAC_MAX_GENERATORS];
unsigned long ords[JAC_MAX_GENERATORS];
unsigned long q[MPZ_MAX_UI_PP_FACTORS], h[MPZ_MAX_UI_PP_FACTORS];
int i, j, k, two_rank, q_rank, cnt;
unsigned long m, n, e, e2, o, p, order, M, W, M2, W2;
unsigned long SylowLimit, abandoned_q;
double x, z;
long t;
int sts, full, ambiguous_exponent,tor3;
if ( ! init ) { mpz_init (Z); init = 1; }
full = 0;
p = (unsigned long)_ff_p;
x = sqrt((double)p);
if ( a1 != JAC_INVALID_A1 ) {
#if HECURVE_GENUS == 2
t = (long)(p*p+1) + (long)(p+1)*a1 + (a1*a1)/2 - (long)2*p;
if ( t > (long)Min ) Min = (unsigned long) t;
t = (long)(p*p+1) + (long)(p+1)*a1 + (a1*a1)/4 + (long)2*p + 1;
if ( t < (long)Max ) Max = (unsigned long)t;
z = (double)a1/x;
for ( i = 0 ; g2a2tab[i].a1 < z ; i++ );
i--;
M = (p*p+1) + (p+1)*a1 + g2a2tab[i].a2median*p ;
W = (unsigned long) ceil(g2a2tab[i].a2mae*p);
#endif
#if HECURVE_GENUS == 3
t = (long)(p*p*p +1) + (long)(p*p+1)*a1 + ((a1*a1)/2 - (long)3*p)*(p+1) - 20*p*(long)ceil(x);
if ( t > (long)Min ) Min = (unsigned long) t;
t = (long)(p*p*p+1) + (long)(p*p+1)*a1 + ((a1*a1)/3 + (long)3*p + 1)*(p+1) + 20*p*(long)ceil(x);
if ( t < (long)Max ) Max = (unsigned long)t;
z = (double)a1/x;
for ( i = 0 ; g3a2tab[i].a1 < z ; i++ );
i--;
M =(p*p*p +1) +(p*p+1)*a1 + g3a2tab[i].a2median*p*(p+1);
W = (unsigned long) ceil(g3a2tab[i].a2mae*p*p);
#endif
} else {
M = Min + (Max-Min)/2;
#if HECURVE_GENUS == 1
if ( p < SMALLJAC_FULL_P ) {
W = (unsigned long) ceil(x);
full = 1;
} else {
W = (unsigned long) ceil(0.8488*x);
}
if ( p > (1UL<<28) ) SMALLJAC_M = 8;
#endif
#if HECURVE_GENUS == 2
W = (unsigned long) ceil(0.7905*p*x);
#endif
#if HECURVE_GENUS == 3
err_printf ("%lu: Invalid a1 value in jac_order in genus 3!\n", _ff_p); exit (0);
#endif
}
ambiguous_exponent = 0;
tor3 = 0;
#if HECURVE_GENUS == 1
two_rank = (ff_poly_roots_d3(0,c[0].f)+1)/2;
if ( ! _ff_p1mod3 ) {
tor3 = ff_poly_g1_3tor(c[0].f);
if ( tor3 !=3 && tor3 != 9 ) tor3=1;
}
#else
two_rank = ff_poly_factors (c[0].f, c[0].d)-1;
if ( a1 == JAC_INVALID_A1 )
tor3 = ff_poly_g2_3tor(c[0].f);
#endif
e = ( two_rank >0 ? 2 : 1);
if ( tor3 ) e*=tor3;
for(;;) {
M2 = M/e;
W2 = _ui_ceil_ratio (W,e);
for ( i = 0 ; i < SMALLJAC_RETRIES ; i++ ) {
_jac_random (g, c[0]);
if ( e > 1 ) jac_exp_ui (&g, &g, e, c);
if ( ! _jac_is_identity (g) ) break;
}
if ( i == SMALLJAC_RETRIES ) { ambiguous_exponent = 1; break; }
o = jac_parallel_search (&g, M2, W2, Min/e, _ui_ceil_ratio(Max,e), full, (two_rank?0:1), c);
if ( ! o ) { err_printf ("%lu: search failed with e=%lu, M=%lu, W=%lu, m=%u for element: ", p, e, M, W, SMALLJAC_M); _jac_print(g); return 0; }
e *= o;
if ( fExponentOnly ) continue;
e2 = e;
if ( two_rank > 1&& ! full ) e2 <<= (two_rank-1);
order = _ui_ceil_ratio(Min,e2) * e2;
if ( ! two_rank && ! (order&0x1) ) order += e2;
if ( order > Max ) { err_printf ("%7u: No multiple of exponent %lu in interval (%lu,%lu) with 2-rank %d after computing order %lu with full = %d for element: ", p, e, Min, Max, two_rank, o, full); _jac_print(g); return 0; }
if ( order+e2 > Max ) break;
if ( ! two_rank && !((order+e2)&0x1) && order + 2*e2 > Max ) break;
}
if ( ! two_rank && !(e&0x1) ) { err_printf ("%lu: Even exponent %ld found for group with trivial 2-rank\n", p, e); return 0; }
if ( fExponentOnly ) {
*pP1 = e;
return 1;
}
if ( ambiguous_exponent ) {
n = jac_gops;
e2 = e;
if ( two_rank > 1 && ! full ) e2 <<= (two_rank-1);
dbg_printf ("%9lu: Ambiguous exponent %d, %d possible orders in [%ld,%ld]\n", p, e2, ui_multiples_in_range (e2, Min, Max), Min, Max);
SylowLimit = ceil(sqrt(Max));
k = ui_factor (q, h, e2);
abandoned_q = 0;
for ( i = 0 ; i < k ; i++ ) {
if ( constraints ) {
order = 0;
cnt = 0;
for ( o = _ui_ceil_ratio(Min,e2)*e2 ; o <= Max ; o += e2 ) {
register int *pcon;
for ( pcon = constraints ; *pcon >= 0 ; pcon++ ) {
if ( (o % (2*(p+1))) == *pcon ) {
cnt++;
if ( cnt == 1 ) { order = o; }
}
}
}
if ( cnt == 1 ) { printf ("%lu: Ambiguity resolved via modular constraint.\n", p); break; }
if ( ! cnt ) { err_printf ("%lu: No orders satisfy modularity constraints!\n", p); return 0; }
}
if ( q[i]*e2 <= Max ) {
for ( j = 0, o = e2 ; j < h[i] ; j++, o/= q[i] );
m = Max/o;
mpz_set_ui (Z, q[i]);
while ( mpz_cmp_ui(Z,m) <= 0 ) { M = mpz_get_ui(Z); mpz_mul_ui (Z, Z, q[i]); }
for ( m = M ; m > SylowLimit ; m /= q[i] );
q_rank = jac_sylow (gen, ords, q[i], e2, M, m, c);
if ( q_rank < 0 ) {
info_printf ("%lu: Abandoned large %d-Sylow subgroup computation, m= %lu, SylowLimit = %lu.\n", p, q[i], m, SylowLimit);
if ( abandoned_q ) { err_printf ("%lu: Abandoned second %d-Sylow subgroup computation - this should be impossible Max = %lu, m = %lu, SylowLimit = %lu\n", p, q[i], Max, m, SylowLimit); return 0; }
abandoned_q = q[i];
}
for ( j = 0 ; j < q_rank ; j++ ) o *= ords[j];
if ( o > e2 ) {
dbg_printf ("%7u: %d-Sylow computation enlarged subgroup to %lu\n", p, q[i], o);
e2 = o;
} else {
dbg_printf ("%7u: %d-Sylow computation failed to enlarge subgroup\n", p, q[i]);
}
order = _ui_ceil_ratio(Min,e2)*e2;
if ( ! two_rank && ! (order&0x1) ) order += e2;
if ( order > Max ) { err_printf ("%lu: No multiple of subgroup order %lu in interval (%lu,%lu) after %d-Sylow computation, 2-rank = %d\n", p, e2, Min, Max, q[i], two_rank); return 0; }
if ( order + e2 > Max ) break;
if ( ! two_rank && !((order+e2)&0x1) && order + 2*e2 > Max ) break;
order = 0;
}
}
jac_ambexp_gops += jac_gops-n;
if ( i == k ) {
#if HECURVE_GENUS == 3
info_printf ("%lu: Maximal subgroup order %lu is ambiguous in (%lu,%lu)\n", p, e2, Min, Max); *pP1 = e2; return ui_multiples_in_range (e2, Min, Max);
#else
if ( ! abandoned_q ) { err_printf ("%lu: Scanned all Sylow subgroups and maximal order %lu is still ambiguous in (%lu,%lu)\n", p, e2, Min, Max); *pP1 = e2; return ui_multiples_in_range (e2, Min, Max); }
for ( order = e2 ; order < Min ; order *= abandoned_q );
if ( order > Max ) { err_printf ("%lu: No %lu-multitple of subgroup order %lu in interval (%lu,%lu) after all but one Sylow subgroups computed, 2-rank = %d\n",
p, abandoned_q, e2, Min, Max, two_rank); return 0; }
info_printf ("%lu: Ambiguity resolved by computing all but 1 Sylow subgroup using %d group operations\n", p, jac_gops-n);
#endif
}
info_printf ("%lu: Ambiguity resolved using %d group operations\n", p, jac_gops-n);
}
*pP1 = order;
return 1;
}
unsigned long jac_parallel_search (jac_t a[1], unsigned long M, unsigned long W, unsigned long Min, unsigned long Max, int full, int parity, curve_t c[1])
{
jac_t babys[SMALLJAC_M], giants[SMALLJAC_M], gsteps[SMALLJAC_M];
jac_t b[64];
jac_t s1, s2;
register unsigned long GS, dvalue, uvalue;
long e, n, o, o1;
register unsigned i, j, k, cnt;
unsigned baby_steps, baby_span;
register uint32_t value, vstep;
uint32_t matches[SMALLJAC_MAX_MATCHES];
register int sign, stash, fast;
unsigned long tabbits;
int w;
unsigned long p[MPZ_MAX_FACTORS], h[MPZ_MAX_FACTORS];
n = jac_gops;
if ( W == 0 ) { err_printf ("%9u: W == 0 in smalljac_parallel_search, increasing to 1\n", _ff_p); W = 1; }
if ( _jac_is_identity (a[0]) ) { return 1; }
if ( parity ) {
parity = 1;
baby_steps = (unsigned)ceil(sqrt((double)W/2.0));
if ( M&0x1 ) M--;
} else {
if ( full < 2 ) {
baby_steps = (unsigned)ceil(sqrt((double)W));
} else {
baby_steps = (unsigned)ceil(sqrt((double)2.0*W));
}
}
baby_span = (parity ? 2*SMALLJAC_M*_ui_ceil_ratio(baby_steps,SMALLJAC_M) : SMALLJAC_M*_ui_ceil_ratio(baby_steps,SMALLJAC_M));
if ( baby_span >= (1<<SMALLJAC_VBITS) ) { err_printf ("SMALLJAC_VBITS = %d is too small for baby span %d, increase SMALLJAC_VBITS\n", SMALLJAC_VBITS, baby_span); exit (0); }
stash = baby_span;
if ( stash >= SMALLJAC_BABY_STASHSIZE ) stash = 0;
_jac_set (babys[0], a[0]);
for ( i = 1 ; i < SMALLJAC_M ; i += i ) jac_parallel_mult_1 (babys+i, babys, babys+i-1, c, i);
if ( ! stash ) {
for ( i = 0 ; (1<<i) <= SMALLJAC_M ; i++ ) _jac_set (b[i], babys[(1<<i)-1]);
for ( i-- ; i < SMALLJAC_VBITS ; i++ ) _jac_square (b[i+1], b[i], c[0]);
}
if ( parity ) {
for ( i = 2 ; i < SMALLJAC_M ; i += 2 ) _jac_set (babys[(i+1)/2], babys[i]);
_jac_set (s1, babys[SMALLJAC_M-1]);
jac_parallel_mult_1(babys+SMALLJAC_M/2, babys, &s1, c, SMALLJAC_M/2);
_jac_mult (s1, babys[0], babys[SMALLJAC_M-1], c[0]);
vstep = 2;
} else {
_jac_set (s1, babys[SMALLJAC_M-1]);
vstep = 1;
}
_jac_set_identity (baby_stash[0]);
for ( tabbits = 8 ; (1<<tabbits) < 2*baby_steps ; tabbits++ );
smalljac_table_init (tabbits);
smalljac_table_insert (baby_stash, 0);
o = 0;
value = 1;
n = jac_gops;
if ( stash ) {
for (;; ) {
for ( i = 0 ; i < SMALLJAC_M ; i++ ) {
if ( _jac_is_identity (babys[i]) ) { o = value; goto found; }
smalljac_table_insert (babys+i, value);
_jac_set (baby_stash[value], babys[i]);
value += vstep;
}
if ( value > baby_span ) break;
jac_parallel_mult_1 (babys, babys, &s1, c, SMALLJAC_M);
}
} else {
for (;; ) {
for ( i = 0 ; i < SMALLJAC_M ; i++ ) {
if ( _jac_is_identity (babys[i]) ) { o = value; goto found; }
smalljac_table_insert (babys+i, value);
value += vstep;
}
if ( value > baby_span ) break;
jac_parallel_mult_1 (babys, babys, &s1, c, SMALLJAC_M);
}
}
value -= vstep;
jac_baby_gops += jac_gops-n;
e = M/value;
if ( parity && (e&1) ) e++;
M = e * value;
n = jac_gops;
jac_exp_ui (giants, babys+SMALLJAC_M-1, e, c);
jac_exp_gops += jac_gops-n;
_jac_square (s1, babys[SMALLJAC_M-1], c[0]);
if ( parity ) {
if ( full < 2 ) GS = 2*value;
else GS = ( (value&1) ? value+1 : value );
} else {
_jac_mult (s1, s1, a[0], c[0]);
if ( full < 2 ) GS = 2*value+1; else GS = value;
}
for ( i = 1 ; i < SMALLJAC_M/2 ; i++ ) _jac_mult (giants[i], giants[i-1], s1, c[0]);
for ( i = 1 ; i < SMALLJAC_M/2 ; i += i ) _jac_square (s1, s1, c[0]);
_jac_set (s2, s1);
if ( _jac_is_identity (s2) ) { o = GS*(SMALLJAC_M/2); goto found; }
_jac_invert (s2);
jac_parallel_mult_1 (giants+SMALLJAC_M/2, giants, &s2, c, SMALLJAC_M/2);
for ( i = 0 ; i < SMALLJAC_M/2 ; i++ ) {
_jac_set (gsteps[i],s1);
_jac_set (gsteps[i+SMALLJAC_M/2],s2);
}
uvalue = M;
dvalue = M-GS;
o = o1 = 0;
for ( j = 0 ; ; j++ ) {
if ( uvalue ) {
for ( i = 0 ; i < SMALLJAC_M/2 ; i++ ) {
if ( (cnt = smalljac_table_lookup (matches, giants+i)) > 0 ) {
for ( k = 0 ; k < cnt ; k++ ) {
if ( stash ) {
sign = _jac_cmp (baby_stash[matches[k]], giants[i]);
} else {
jac_exp_ui32_powers (&s1, b, matches[k], c);
sign = _jac_cmp (s1, giants[i]);
}
if ( sign ) {
if ( o ) o1 = o;
o = ( sign > 0 ? uvalue - matches[k] : uvalue + matches[k] );
if ( ! o ) { o = o1; continue; }
if ( o < 0 ) o = -o;
if ( ! full ) goto found;
if ( o == o1 ) continue;
if ( o1 ) { o = ( o > o1 ? o-o1 : o1-o); goto found; }
if ( full < 2 && j && 2*o > Max-Min ) {
if ( ! dvalue ) return o;
w = ui_factor (p, h, o);
if ( w == 1 && h[0] == 1 ) { jac_order_count++; jac_giant_gops += jac_gops-n; return o; }
if ( p[w-1] > o-Min && (vstep*o/p[w-1])+dvalue+baby_span < o ) {
jac_order_count++; jac_giant_gops += jac_gops-n; return o;
}
uvalue = 0;
goto udone;
}
}
}
}
if ( uvalue ) uvalue += GS;
}
}
udone:
if ( dvalue ) {
for ( i = SMALLJAC_M-1 ; dvalue && i >= SMALLJAC_M/2 ; i-- ) {
if ( (cnt = smalljac_table_lookup (matches, giants+i)) > 0 ) {
for ( k = 0 ; k < cnt ; k++ ) {
if ( stash ) {
sign = _jac_cmp (baby_stash[matches[k]], giants[i]);
} else {
jac_exp_ui32_powers (&s1, b, matches[k], c);
sign = _jac_cmp (s1, giants[i]);
}
if ( sign ) {
if ( o ) o1 = o;
o = ( sign > 0 ? dvalue - matches[k] : dvalue + matches[k] );
if ( ! o ) { o = o1; continue; }
if ( o < 0 ) o = -o;
if ( ! full ) goto found;
if ( o == o1 ) continue;
if ( o1 ) { o = ( o > o1 ? o-o1 : o1-o); goto found; }
if ( full < 2 && 2*o < Max-Min ) {
if ( ! uvalue ) return o;
w = ui_factor (p, h, o);
if ( w == 1 && h[0] == 1 ) { jac_order_count++; jac_giant_gops += jac_gops-n; return o; }
if ( p[w-1] > Max-o && (vstep*o/p[w-1])+o+baby_span < uvalue ) {
jac_order_count++; jac_giant_gops += jac_gops-n; return o;
}
dvalue = 0;
goto ddone;
}
}
}
}
if ( dvalue <= GS ) dvalue = 0; else dvalue -= GS;
}
}
ddone:
if ( uvalue > Max+baby_span ) uvalue = 0;
if ( dvalue+baby_span < Min ) dvalue = 0;
if ( ! dvalue && ! uvalue ) break;
if ( ! dvalue ) {
jac_parallel_mult_c (giants, giants, gsteps, c, SMALLJAC_M/2);
} else if ( ! uvalue ) {
jac_parallel_mult_c (giants+SMALLJAC_M/2, giants+SMALLJAC_M/2, gsteps+SMALLJAC_M/2, c, SMALLJAC_M/2);
} else {
jac_parallel_mult_c (giants, giants, gsteps, c, SMALLJAC_M);
}
}
jac_giant_gops += jac_gops-n;
if ( ! o ) {
err_printf ("%lu: No exponent found in smalljac_parallel_search, full=%d, parity=%d, baby_span = %d, GS = %ld, dvalue = %d, uvalue = %ld, Min = %lu, Max = %lu!\n",
_ff_p, full, parity, baby_span, GS, dvalue, uvalue, Min, Max); _curve_print(c[0]);
_jac_print(a[0]);
return 0;
}
if ( o < 0 ) { err_printf("%lu: Negative exponent %ld found with full=%d, o1=%ld for element ", _ff_p, o, full, o1); _jac_print(a[0]); return 0; }
return o;
found:
if ( ! o ) { err_printf("%lu: Zero exponent found with full=%d, o1=%ld for element ", _ff_p, full, o1); _jac_print(a[0]); exit (0); }
if ( o < 0 ) { err_printf("%lu: Negative exponent %ld found with full=%d, o1=%ld for element ", _ff_p, o, full, o1); _jac_print(a[0]); return 0; }
jac_giant_gops += jac_gops-n;
n = jac_gops;
w = ui_factor (p, h, o);
jac_factored_order_ui (&o, a, p, h, w, c);
jac_fastorder_gops += jac_gops-n;
if ( o < 0 ) { err_printf("%lu: Negative exponent %ld after fastorder with full=%d, o1=%ld for element ", _ff_p, o, full, o1); _jac_print(a[0]); return 0; }
return o;
}
int jac_search (mpz_t e[2], jac_t a[1], unsigned m, mpz_t Min, mpz_t Max, curve_t c[1])
{
static int init;
static mpz_t o, o1, o2, G;
jac_t b[32], baby, giant;
jac_t s1, step, babystep;
unsigned long S, tabbits;
unsigned i, j, k, s, cnt;
uint32_t matches[SMALLJAC_MAX_MATCHES];
int sign;
if ( ! init ) { mpz_init (o); mpz_init(o1); mpz_init (o2); mpz_init(G); init = 1; }
mpz_sub (G, Max, Min);
S = mpz_get_ui (G);
s = (unsigned) ceil(sqrt(_ui_ceil_ratio(S, m)));
for ( tabbits = 8 ; (1<<tabbits) < 2*s ; tabbits++ );
smalljac_table_init (tabbits);
_jac_set_identity (step);
smalljac_table_insert (&step, 0);
jac_exp_ui (&babystep, a, m, c);
_jac_set (baby, babystep);
_jac_set (b[0], babystep);
for ( i = 1 ; i < 32 ; i++ ) _jac_square(b[i], b[i-1], c[0]);
mpz_set(G, Min);
mpz_add_ui (G, G, (unsigned long)s*(unsigned long)m);
jac_exp_mpz (&giant, a, G, c);
S = 2*(unsigned long)s*(unsigned long)m;
jac_exp_ui (&step, a, S, c);
for ( i = 1 ; ; i++ ) {
smalljac_table_insert (&baby, i);
if ( i > s ) break;
_jac_mult (baby, baby, babystep, c[0]);
}
for (;;) {
mpz_set (o, G);
mpz_add_ui (o, o, (unsigned long)s*(S-(unsigned long)m));
if ( mpz_cmp (o, Max) <= 0 ) break;
s--;
}
mpz_set_ui (o, 0);
mpz_set_ui (o1, 0); mpz_set_ui (o2, 0);
for ( j = 0 ; j < s ; j++ ) {
if ( (cnt = smalljac_table_lookup (matches, &giant)) > 0 ) {
for ( k = 0 ; k < cnt ; k++ ) {
if ( matches[k] ) {
jac_exp_ui32_powers (&s1, b, matches[k], c);
if ( (sign = _jac_cmp(s1,giant)) ) {
mpz_set(o, G);
mpz_add_ui (o, o, j*S);
if ( sign > 0 ) { mpz_sub_ui (o, o, (unsigned long)matches[k]*(unsigned long)m); } else { mpz_add_ui (o, o, (unsigned long)matches[k]*(unsigned long)m); }
} else {
mpz_set_ui (o, 0);
}
} else {
mpz_set (o, G);
mpz_add_ui (o, o, j*S);
}
if ( mpz_sgn(o) && mpz_cmp(o,Min) >= 0 && mpz_cmp (o,Max) <= 0 ) {
if ( ! mpz_sgn(o1) ) {
mpz_set (o1, o);;
} else {
if ( mpz_cmp(o,o1) < 0 ) {
mpz_set (o2, o1); mpz_set (o1, o);
} else if ( mpz_cmp(o,o1) > 0 && (! mpz_sgn(o2) || mpz_cmp(o,o2) < 0) ) {
mpz_set (o2, o);
}
}
}
}
}
if ( j == s ) break;
_jac_mult (giant, giant, step, c[0]);
}
mpz_set (e[0], o1);
mpz_set (e[1], o2);
return ( mpz_sgn(o2) ? 2 : ( mpz_sgn(o1) ? 1 : 0 ));
}