aboutsummaryrefslogtreecommitdiff
path: root/src/cm/custom.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cm/custom.c')
-rw-r--r--src/cm/custom.c212
1 files changed, 212 insertions, 0 deletions
diff --git a/src/cm/custom.c b/src/cm/custom.c
new file mode 100644
index 0000000..fd58364
--- /dev/null
+++ b/src/cm/custom.c
@@ -0,0 +1,212 @@
+/*
+ * ecgen, tool for generating Elliptic curve domain parameters
+ * Copyright (C) 2017 J08nY
+ */
+#include "custom.h"
+#include "io/output.h"
+#include "obj/curve.h"
+#include "obj/point.h"
+#include "obj/subgroup.h"
+#include "util/bits.h"
+
+static size_t custom_add_primes(GEN r, GEN order, GEN **primes,
+ size_t nprimes) {
+ debug_log("add_primes r = %Pi, nprimes = %lu", r, nprimes);
+ size_t nalloc = nprimes;
+ if (nprimes == 0) {
+ nalloc = 10;
+ *primes = try_calloc(sizeof(GEN) * nalloc);
+ }
+
+ GEN logN = ground(glog(order, BIGDEFAULTPREC));
+
+ GEN rlog = mulii(r, logN);
+ GEN rplog = mulii(addis(r, 1), logN);
+
+ forprime_t iter;
+ forprime_init(&iter, rlog, rplog);
+ GEN prime;
+ while ((prime = forprime_next(&iter))) {
+ long k = kronecker(order, prime);
+ if (k == 1) {
+ GEN pstar = prime;
+ GEN ppow = divis(subis(prime, 1), 2);
+ if (mod2(ppow) == 1) {
+ pstar = negi(prime);
+ } else {
+ pstar = gcopy(pstar);
+ }
+ if (nprimes == nalloc) {
+ nalloc *= 2;
+ *primes = try_realloc(*primes, sizeof(GEN) * nalloc);
+ }
+ (*primes)[nprimes++] = pstar;
+ }
+ }
+
+ *primes = try_realloc(*primes, sizeof(GEN) * nprimes);
+
+ return nprimes;
+}
+
+static void custom_quadr_init(custom_quadr_t *quadr, GEN order) {
+ quadr->D = gen_0;
+ quadr->p = gen_0;
+ quadr->t = gen_0;
+
+ quadr->order = order;
+ quadr->r = gen_0;
+ quadr->i = gen_0;
+ quadr->Sp = NULL;
+ quadr->nprimes = 0;
+}
+
+static void custom_quadr_next(custom_quadr_t *quadr) {
+ // Ok I get some state in r, i, Sp and nprimes.
+ // Here I want to check if I want to generate more primes into Sp
+ // Then continue with i
+
+ GEN logN = ground(glog(quadr->order, BIGDEFAULTPREC));
+ GEN rlog2 = sqri(mulii(addis(quadr->r, 1), logN));
+
+ // When do I want more primes? If i == imax, or nprimes == 0
+ GEN imax = int2n(quadr->nprimes);
+ if (equalii(quadr->i, imax) || quadr->nprimes == 0) {
+ quadr->nprimes = custom_add_primes(quadr->r, quadr->order, &(quadr->Sp),
+ quadr->nprimes);
+ }
+
+ while (true) {
+ imax = int2n(quadr->nprimes);
+
+ while (cmpii(quadr->i, imax) < 0) {
+ // debug_log("i %Pi", quadr->i);
+ pari_sp btop = avma;
+ GEN pprod = gen_1;
+ bits_t *ibits = bits_from_i_len(quadr->i, quadr->nprimes);
+ for (size_t j = 0; j < quadr->nprimes; ++j) {
+ if (GET_BIT(ibits->bits, j) == 1) {
+ // debug_log("multiplying %Pi", quadr->Sp[j]);
+ pprod = mulii(pprod, quadr->Sp[j]);
+ }
+ }
+ bits_free(&ibits);
+
+ GEN absp = absi(pprod);
+ long m4 = mod4(absp);
+ if (cmpii(absp, rlog2) < 0 && equalii(modis(pprod, 8), stoi(5)) &&
+ m4 != 1 && m4 != 2) {
+ debug_log("candidate D = %Pi", pprod);
+ GEN x;
+ GEN y;
+ if (!cornacchia2(absp, quadr->order, &x, &y)) {
+ avma = btop;
+ quadr->i = addis(quadr->i, 1);
+ // debug_log("Cornacchia fail");
+ continue;
+ }
+ GEN pp1 = addii(addis(quadr->order, 1), x);
+ GEN pp2 = subii(addis(quadr->order, 1), x);
+ if (isprime(pp1)) {
+ quadr->p = pp1;
+ quadr->D = pprod;
+ quadr->t = x;
+ quadr->i = addis(quadr->i, 1);
+ debug_log("good D %Pi", pprod);
+ return;
+ }
+ if (isprime(pp2)) {
+ quadr->p = pp2;
+ quadr->D = pprod;
+ quadr->t = x;
+ quadr->i = addis(quadr->i, 1);
+ debug_log("good D %Pi", pprod);
+ return;
+ }
+ }
+ avma = btop;
+ quadr->i = addis(quadr->i, 1);
+ }
+
+ quadr->r = addis(quadr->r, 1);
+ quadr->nprimes = custom_add_primes(quadr->r, quadr->order, &(quadr->Sp),
+ quadr->nprimes);
+ rlog2 = sqri(mulii(addis(quadr->r, 1), logN));
+ }
+}
+
+static void custom_quadr_free(custom_quadr_t *quadr) { try_free(quadr->Sp); }
+
+curve_t *custom_curve() {
+ GEN order = strtoi(cfg->cm_order);
+ if (!isprime(order)) {
+ fprintf(err, "Currently, order must be prime for CM to work.\n");
+ return NULL;
+ }
+
+ GEN a = NULL;
+ GEN e = NULL;
+ GEN g = NULL;
+
+ custom_quadr_t quadr;
+ custom_quadr_init(&quadr, order);
+ while (true) {
+ custom_quadr_next(&quadr);
+
+ debug_log("order = %Pi", order);
+ debug_log("p = %Pi, t = %Pi, D = %Pi, ", quadr.p, quadr.t, quadr.D);
+ GEN H = polclass(quadr.D, 0, 0);
+
+ debug_log("H = %Ps", H);
+
+ GEN r = FpX_roots(H, quadr.p);
+ debug_log("roots = %Ps", r);
+ if (gequal(r, gtovec(gen_0))) {
+ continue;
+ }
+
+ bool has_curve = false;
+
+ long rlen = glength(r);
+ for (long i = 1; i <= rlen; ++i) {
+ GEN root = gel(r, i);
+ a = Fp_div(
+ Fp_mul(stoi(27), root, quadr.p),
+ Fp_mul(stoi(4), Fp_sub(stoi(1728), root, quadr.p), quadr.p),
+ quadr.p);
+ e = ellinit(mkvec2(a, negi(a)), quadr.p, 0);
+ pari_CATCH(e_TYPE) { continue; }
+ pari_TRY { checkell(e); };
+ pari_ENDCATCH{};
+
+ g = genrand(e);
+ GEN gmul = ellmul(e, g, order);
+ if (ell_is_inf(gmul)) {
+ debug_log("YES %Ps", e);
+ has_curve = true;
+ break;
+ }
+ }
+
+ if (has_curve) break;
+ }
+
+ custom_quadr_free(&quadr);
+
+ curve_t *result = curve_new();
+ result->field = quadr.p;
+ result->a = a;
+ result->b = negi(a);
+ result->curve = e;
+ result->order = order;
+ result->generators = subgroups_new(1);
+ result->generators[0] = subgroup_new();
+ result->generators[0]->generator = point_new();
+ result->generators[0]->generator->point = g;
+ result->generators[0]->generator->order = order;
+ result->generators[0]->generator->cofactor = stoi(1);
+ result->generators[0]->npoints = 0;
+ result->ngens = 1;
+
+ return result;
+} \ No newline at end of file