/*
Copyright (C) 2015 Kushagra Singh
This file is part of FLINT.
FLINT is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. See .
*/
#include
#include "flint.h"
#include "fmpz.h"
#include "mpn_extras.h"
/* Select Montgomery Elliptic Curve given a sigma
(Suyama's parameterization)
Returns 1 in case factor is found while selecting
the curve. */
/* Also selects initial point Q0 [x0 :: z0] (z0 = 1) */
int
fmpz_factor_ecm_select_curve(mp_ptr f, mp_ptr sig, mp_ptr n, ecm_t ecm_inf)
{
mp_size_t sz, cy;
mp_size_t invlimbs, gcdlimbs;
mp_ptr temp, tempv, tempn, tempi, tempf;
int ret;
TMP_INIT;
TMP_START;
temp = TMP_ALLOC(ecm_inf->n_size * sizeof(mp_limb_t));
tempv = TMP_ALLOC((ecm_inf->n_size) * sizeof(mp_limb_t));
tempn = TMP_ALLOC((ecm_inf->n_size) * sizeof(mp_limb_t));
tempi = TMP_ALLOC((ecm_inf->n_size + 1) * sizeof(mp_limb_t));
tempf = TMP_ALLOC((ecm_inf->n_size + 1) * sizeof(mp_limb_t));
mpn_zero(tempn, ecm_inf->n_size);
mpn_zero(tempv, ecm_inf->n_size);
mpn_zero(temp, ecm_inf->n_size);
flint_mpn_copyi(ecm_inf->u, sig, ecm_inf->n_size);
temp[0] = UWORD(4);
ret = 0;
if (ecm_inf->normbits)
mpn_lshift(temp, temp, ecm_inf->n_size, ecm_inf->normbits); /* temp = (4 << norm) */
flint_mpn_mulmod_preinvn(ecm_inf->v, ecm_inf->u, temp, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
flint_mpn_mulmod_preinvn(ecm_inf->w, ecm_inf->u, ecm_inf->u, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
mpn_add_n(temp, temp, ecm_inf->one, ecm_inf->n_size); /* temp = (5 << norm) */
fmpz_factor_ecm_submod(ecm_inf->u, ecm_inf->w, temp, n, ecm_inf->n_size);
flint_mpn_mulmod_preinvn(ecm_inf->w, ecm_inf->u, ecm_inf->u, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
flint_mpn_mulmod_preinvn(ecm_inf->x, ecm_inf->w, ecm_inf->u, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
flint_mpn_mulmod_preinvn(ecm_inf->w, ecm_inf->v, ecm_inf->v, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
flint_mpn_mulmod_preinvn(ecm_inf->z, ecm_inf->w, ecm_inf->v, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
flint_mpn_mulmod_preinvn(ecm_inf->w, ecm_inf->x, ecm_inf->v, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
mpn_sub_n(temp, temp, ecm_inf->one, ecm_inf->n_size); /* temp = (4 << norm) */
flint_mpn_mulmod_preinvn(ecm_inf->t, ecm_inf->w, temp, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
mpn_sub_n(temp, temp, ecm_inf->one, ecm_inf->n_size); /* temp = (3 << norm) */
flint_mpn_mulmod_preinvn(ecm_inf->w, ecm_inf->u, temp, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
fmpz_factor_ecm_submod(ecm_inf->u, ecm_inf->v, ecm_inf->u, n, ecm_inf->n_size);
fmpz_factor_ecm_addmod(ecm_inf->v, ecm_inf->v, ecm_inf->w, n, ecm_inf->n_size);
flint_mpn_mulmod_preinvn(ecm_inf->w, ecm_inf->u, ecm_inf->u, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
flint_mpn_mulmod_preinvn(ecm_inf->u, ecm_inf->u, ecm_inf->w, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
flint_mpn_mulmod_preinvn(ecm_inf->a24, ecm_inf->u, ecm_inf->v, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
flint_mpn_mulmod_preinvn(ecm_inf->v, ecm_inf->t, ecm_inf->z, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
sz = ecm_inf->n_size;
MPN_NORM(ecm_inf->v, sz); /* sz has number of limbs of v */
if (sz == 0) /* v = 0, gcd(0, n) = n. Hence inverse will not exist. */
{ /* No point in further computation with curve */
ret = (-1);
goto cleanup;
}
flint_mpn_copyi(tempv, ecm_inf->v, sz);
flint_mpn_copyi(tempn, n, ecm_inf->n_size);
gcdlimbs = mpn_gcdext(tempf, tempi, &invlimbs, tempv, sz, tempn, ecm_inf->n_size);
if (!(gcdlimbs == 1 && tempf[0] == ecm_inf->one[0]) &&
!(gcdlimbs == ecm_inf->n_size && mpn_cmp(tempf, n, ecm_inf->n_size) == 0))
{
/* Found factor */
flint_mpn_copyi(f, tempf, gcdlimbs);
ret = gcdlimbs;
goto cleanup;
}
if (invlimbs < 0) /* negative inverse, add n */
{
invlimbs *= -1;
if (ecm_inf->normbits)
{
cy = mpn_lshift(tempi, tempi, invlimbs, ecm_inf->normbits);
if (cy)
tempi[invlimbs] = cy;
}
mpn_sub_n(tempi, n, tempi, ecm_inf->n_size);\
}
else
{
if (ecm_inf->normbits)
{
cy = mpn_lshift(tempi, tempi, invlimbs, ecm_inf->normbits);
if (cy)
tempi[invlimbs] = cy;
}
}
MPN_NORM(tempi, invlimbs);
mpn_zero(ecm_inf->u, ecm_inf->n_size);
flint_mpn_copyi(ecm_inf->u, tempi, invlimbs);
flint_mpn_mulmod_preinvn(ecm_inf->v, ecm_inf->u, ecm_inf->t, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
flint_mpn_mulmod_preinvn(ecm_inf->x, ecm_inf->x, ecm_inf->v, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
flint_mpn_mulmod_preinvn(ecm_inf->v, ecm_inf->u, ecm_inf->z, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
flint_mpn_mulmod_preinvn(ecm_inf->w, ecm_inf->a24, ecm_inf->v, ecm_inf->n_size,
n, ecm_inf->ninv, ecm_inf->normbits);
mpn_zero(temp, sz);
temp[0] = UWORD(2);
if (ecm_inf->normbits)
mpn_lshift(temp, temp, ecm_inf->n_size, ecm_inf->normbits);
fmpz_factor_ecm_addmod(ecm_inf->a24, ecm_inf->w, temp, n, ecm_inf->n_size);
mpn_rshift(ecm_inf->a24, ecm_inf->a24, ecm_inf->n_size, 2);
if (ecm_inf->normbits)
ecm_inf->a24[0] &= ~((UWORD(1)<normbits) - 1);
flint_mpn_copyi(ecm_inf->z, ecm_inf->one, ecm_inf->n_size);
cleanup:
TMP_END;
return ret;
}