aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/release.yml16
-rw-r--r--.github/workflows/test.yml12
-rw-r--r--CMakeLists.txt8
-rw-r--r--Doxyfile2
-rw-r--r--README.md2
-rw-r--r--src/cm/anomalous.c4
-rw-r--r--src/cm/anomalous.h4
-rw-r--r--src/cm/cm.c20
-rw-r--r--src/cm/cm.h2
-rw-r--r--src/cm/cm_any.c346
-rw-r--r--src/cm/cm_any.h49
-rw-r--r--src/cm/cm_prime.c58
-rw-r--r--src/cm/p1363.c2
-rw-r--r--src/ecgen.c13
-rw-r--r--src/exhaustive/ansi.c2
-rw-r--r--src/exhaustive/brainpool.c4
-rw-r--r--src/exhaustive/check.c2
-rw-r--r--src/exhaustive/exhaustive.c12
-rw-r--r--src/exhaustive/exhaustive.h2
-rw-r--r--src/exhaustive/family.c14
-rw-r--r--src/exhaustive/family.h7
-rw-r--r--src/exhaustive/nums.c5
-rw-r--r--src/exhaustive/nums.h2
-rw-r--r--src/gen/gens.c13
-rw-r--r--src/gen/hex.c2
-rw-r--r--src/gen/metadata.c3
-rw-r--r--src/gen/order.c2
-rw-r--r--src/invalid/invalid.c5
-rw-r--r--src/invalid/invalid.h2
-rw-r--r--src/io/cli.c6
-rw-r--r--src/io/cli.h4
-rw-r--r--src/io/input.c2
-rw-r--r--src/io/input.h2
-rw-r--r--src/io/output.c23
-rw-r--r--src/io/output.h20
-rw-r--r--src/math/koblitz.c2
-rw-r--r--src/math/subgroup.c8
-rw-r--r--src/math/twists.c2
-rw-r--r--src/misc/compat.h21
-rw-r--r--src/misc/config.c4
-rw-r--r--src/misc/config.h4
-rw-r--r--src/obj/curve.c2
-rw-r--r--src/obj/obj.h20
-rw-r--r--src/obj/point.c2
-rw-r--r--src/util/bits.c8
-rw-r--r--src/util/memory.c2
-rw-r--r--src/util/random.c5
-rw-r--r--src/util/str.c3
-rw-r--r--src/util/timeout.c8
-rw-r--r--src/util/timeout.h8
-rw-r--r--test/common.sh8
-rwxr-xr-xtest/ecgen.sh55
-rw-r--r--test/src/util/test_bits.c4
53 files changed, 588 insertions, 250 deletions
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 61c8fc3..170ce0f 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -9,7 +9,7 @@ jobs:
release:
runs-on: ubuntu-24.04
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
with:
submodules: true
- name: Setup pari
@@ -20,7 +20,19 @@ jobs:
run: |
make
strip ecgen
+ mv ecgen ecgen-release
+ make clean
+ make STATIC=1
+ mv ecgen ecgen-static
+ make clean
+ make DEBUG=1
+ mv ecgen ecgen-debug
+ make clean
+ mv ecgen-release ecgen
- name: Release
uses: softprops/action-gh-release@v2
with:
- files: ecgen
+ files: |
+ ecgen
+ ecgen-static
+ ecgen-debug
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 59de7c8..76d9ecf 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,13 +11,21 @@ jobs:
env:
CC: ${{ matrix.CC }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
with:
submodules: true
- name: Setup pari
run: |
sudo apt-get update
sudo apt-get install -y libpari-dev pari-gp pari-seadata meson ninja-build
+ - name: Build
+ run: |
+ make
+ make clean
+ make STATIC=1
+ make clean
+ make DEBUG=1
+ make clean
- name: Test
run: |
TEST=1 make unittest
@@ -26,7 +34,7 @@ jobs:
run: |
cd src && find . -name "*.gcda" -exec gcov -pb "{}" +;
- name: Code coverage upload
- uses: codecov/codecov-action@v4
+ uses: codecov/codecov-action@v5
if: ${{ matrix.CC == 'gcc' }}
with:
env_vars: CC
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 04d8f36..a08c21c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -28,4 +28,10 @@ else ()
set(PLATFORM_SPECIFIC_LIBS rt)
endif()
-target_link_libraries(ecgen pthread pari parson sha1 ${PLATFORM_SPECIFIC_LIBS})
+if (STATIC)
+ # Find the static libpari library
+ find_library(PARI_STATIC NAMES libpari.a)
+ target_link_libraries(ecgen pthread ${PARI_STATIC} parson sha1 ${PLATFORM_SPECIFIC_LIBS})
+else ()
+ target_link_libraries(ecgen pthread pari parson sha1 ${PLATFORM_SPECIFIC_LIBS})
+endif()
diff --git a/Doxyfile b/Doxyfile
index 8fa8e6a..4e04c75 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = "ecgen"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 0.7.7
+PROJECT_NUMBER = 0.8.2
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/README.md b/README.md
index 65b5d23..72b25f1 100644
--- a/README.md
+++ b/README.md
@@ -50,7 +50,7 @@ Tool for generating Elliptic curve domain parameters.
- `-d / --data-dir=DIR` Set PARI/GP data directory (containing seadata package).
- `-m / --memory=SIZE` Use PARI stack of `SIZE` (can have suffix k/m/g).
- - `--threads=NUM` Use `NUM` threads.
+ - `--threads=NUM` Use `NUM` threads (in PARI or invalid generation).
- `--thread-stack=SIZE` Use PARI stack of `SIZE` (per thread, can have suffix k/m/g).
- `--timeout=TIME` Timeout computation of a curve parameter after `TIME` (can have suffix s/m/h/d).
diff --git a/src/cm/anomalous.c b/src/cm/anomalous.c
index 70df8e4..36d6890 100644
--- a/src/cm/anomalous.c
+++ b/src/cm/anomalous.c
@@ -8,7 +8,7 @@
static disc_t **disc_table;
-void anomalous_init() {
+void anomalous_init(void) {
disc_table = try_calloc(sizeof(disc_t *) * 5);
for (int i = 0; i < 5; ++i) {
disc_table[i] = try_calloc(sizeof(disc_t));
@@ -128,7 +128,7 @@ GENERATOR(anomalous_gen_order) {
return 1;
}
-void anomalous_quit() {
+void anomalous_quit(void) {
if (disc_table) {
for (int i = 0; i < 5; ++i) {
if (disc_table[i]) {
diff --git a/src/cm/anomalous.h b/src/cm/anomalous.h
index 73b84fd..6e897d5 100644
--- a/src/cm/anomalous.h
+++ b/src/cm/anomalous.h
@@ -49,12 +49,12 @@ GENERATOR(anomalous_gen_order);
/**
* @brief Initialize anomalous generation, allocate and set the disc_table.
*/
-void anomalous_init();
+void anomalous_init(void);
/**
* @brief Deinitialize anomalous generation, free the discriminants from the
* disc_table.
*/
-void anomalous_quit();
+void anomalous_quit(void);
#endif // ECGEN_CM_ANOMALOUS_H
diff --git a/src/cm/cm.c b/src/cm/cm.c
index 9dffc1d..649df4d 100644
--- a/src/cm/cm.c
+++ b/src/cm/cm.c
@@ -69,12 +69,14 @@ static void cm_ginit(gen_f *generators, bool prime) {
if (prime) {
generators[OFFSET_CURVE] = &cm_gen_curve_prime;
generators[OFFSET_POINTS] = &points_gen_prime;
+ } else if (GET_BOOL(unique)) {
+ generators[OFFSET_CURVE] = &cm_gen_curve_unique;
} else {
generators[OFFSET_CURVE] = &cm_gen_curve_any;
}
generators[OFFSET_ORDER] = &cm_gen_order;
} else if (cfg->method == METHOD_ANOMALOUS) {
- GET(random); // Used within the method.
+ GET(random); // Used within the method.
generators[OFFSET_FIELD] = &anomalous_gen_field;
generators[OFFSET_A] = &gen_skip;
generators[OFFSET_B] = &anomalous_gen_equation;
@@ -181,10 +183,15 @@ static int cm_init(exhaustive_t *setup) {
for (long j = 1; j <= len; ++j) {
GEN factor = gel(factors, j);
if (isprime(factor)) {
+ debug_log("Adding prime factor %Pi", factor);
addprimes(gtovec(factor));
} else {
- GEN factored = Z_factor(order);
- addprimes(gel(factored, 1));
+ GEN factored = Z_factor(factor);
+ GEN primes = gel(factored, 1);
+ for (long k = 1; k <= glength(primes); ++k) {
+ debug_log("Adding prime factor %Pi", gel(primes, k));
+ addprimes(gel(primes, k));
+ }
}
order = mulii(order, factor);
}
@@ -195,6 +202,10 @@ static int cm_init(exhaustive_t *setup) {
fprintf(err, "Order requested not a number: %s\n", cfg->cm_order);
return 1;
}
+ if (cmpiu(order, 5) < 0) {
+ pari_fprintf(err, "Order requested too small: %Pi\n", order);
+ return 1;
+ }
long ord_log = logint0(order, gen_2, NULL);
if (ord_log > cfg->bits) {
pari_fprintf(err,
@@ -226,10 +237,11 @@ static void cm_quit(exhaustive_t *setup) {
if (cfg->method == METHOD_ANOMALOUS) {
anomalous_quit();
}
+ cm_any_quit();
exhaustive_clear(setup);
}
-int cm_do() {
+int cm_do(void) {
debug_log_start("Starting Complex Multiplication method");
gen_f generators[OFFSET_END] = {NULL};
diff --git a/src/cm/cm.h b/src/cm/cm.h
index b80d987..a130366 100644
--- a/src/cm/cm.h
+++ b/src/cm/cm.h
@@ -15,6 +15,6 @@
*
* @return
*/
-int cm_do();
+int cm_do(void);
#endif // ECGEN_CM_CM_H
diff --git a/src/cm/cm_any.c b/src/cm/cm_any.c
index f948ac1..0e5ed7c 100644
--- a/src/cm/cm_any.c
+++ b/src/cm/cm_any.c
@@ -16,17 +16,22 @@
*/
static void good_qdisc_minimal(cm_any_qdisc_t *qdisc, GEN order) {
pari_sp ltop = avma;
- GEN d = stoi(2);
- size_t j = 0;
+ GEN d;
+ if (qdisc->d) {
+ d = negi(subis(qdisc->d, 1));
+ } else {
+ d = stoi(2);
+ }
+ size_t j = 1;
while (true) {
++j;
+ if (j % 100 == 0) {
+ debug_log("d: %Ps", d);
+ }
if (!issquarefree(d)) {
d = addis(d, 1);
continue;
}
- if (j % 100 == 0) {
- debug_log("D: %Ps", d);
- }
GEN D = quaddisc(negi(d));
GEN K = Buchall(quadpoly(D), 0, DEFAULTPREC);
GEN alphas = bnfisintnorm(K, order);
@@ -52,7 +57,7 @@ static void good_qdisc_minimal(cm_any_qdisc_t *qdisc, GEN order) {
}
}
-/**
+/*
* @brief Find a fundamental quadratic discriminant < d_range, start looking
* at the sides of the inverted Hasse interval around order, upto p_range
*
@@ -114,9 +119,9 @@ static cm_any_qdisc_t *good_qdisc_brute_range(GEN order, GEN p_range, GEN d_rang
return result;
};
}
-
*/
-/**
+/*
+ *
* @brief Find a fundamental quadratic discriminant < order^beta, start looking
* at the sides of the inverted Hasse interval around order, upto
* order^alpha width.
@@ -124,115 +129,105 @@ static cm_any_qdisc_t *good_qdisc_brute_range(GEN order, GEN p_range, GEN d_rang
* @param alpha
* @param beta
* @return
- *//*
-
+ *
static cm_any_qdisc_t *good_qdisc_brute(GEN order, GEN alpha, GEN beta) {
- GEN ord_a = ground(gpow(order, alpha, DEFAULTPREC));
- GEN ord_b = ground(gpow(order, beta, DEFAULTPREC));
- return good_qdisc_brute_range(order, ord_a, ord_b);
+ GEN ord_a = ground(gpow(order, alpha, DEFAULTPREC));
+ GEN ord_b = ground(gpow(order, beta, DEFAULTPREC));
+ return good_qdisc_brute_range(order, ord_a, ord_b);
}
*/
-GEN cm_construct_curve(GEN order, GEN d, GEN p, bool ord_prime) {
+void cm_update_roots(GEN d, GEN p, cm_any_roots_t *roots) {
+ pari_sp ltop = avma;
+ GEN H = polclass(d, 0, 0);
+ GEN raw = FpX_roots(H, p);
+ if (roots->roots && isclone(roots->roots)) {
+ gunclone(roots->roots);
+ }
+ roots->roots = gclone(raw);
+ roots->total = glength(raw);
+ roots->used = 0;
+ avma = ltop;
+}
+
+cm_any_roots_t *cm_make_roots(GEN d, GEN p) {
+ debug_log("Making roots, d = %Pi, p = %Pi", d, p);
+ cm_any_roots_t *roots = try_calloc(sizeof(cm_any_roots_t));
+ cm_update_roots(d, p, roots);
+ return roots;
+}
+
+void cm_free_roots(cm_any_roots_t *roots) {
+ if (roots) {
+ if (roots->roots && isclone(roots->roots)) {
+ gunclone(roots->roots);
+ }
+ try_free(roots);
+ }
+}
+
+GEN cm_construct_curve(GEN order, GEN d, GEN p, cm_any_roots_t *roots,
+ bool ord_prime) {
debug_log("Constructing a curve with N = %Pi, d = %Pi, p = %Pi", order, d,
p);
pari_sp ltop = avma;
- GEN H = polclass(d, 0, 0);
- debug_log("H = %Ps", H);
- GEN r = FpX_roots(H, p);
- debug_log("roots = %Ps", r);
- if (gequal(r, gtovec(gen_0))) {
+ debug_log("roots(%li/%li) = %Ps", roots->used, roots->total, roots->roots);
+ if (roots->total == 0 || roots->used == roots->total ||
+ gequal(roots->roots, gtovec(gen_0))) {
avma = ltop;
return NULL;
}
- long rlen = glength(r);
- for (long i = 1; i <= rlen; ++i) {
- GEN root = gel(r, i);
- debug_log("trying root = %Pi", root);
+ for (long i = roots->used; i < roots->total; ++i) {
+ roots->used = i + 1;
+ GEN root = gel(roots->roots, i + 1);
+ if (gequal(root, gen_0) || equaliu(root, 1728)) {
+ debug_log("skipping root = 0 or 1728");
+ continue;
+ }
+ debug_log("trying root[%i] = %Pi", i + 1, root);
- GEN e = ellinit(ellfromj(mkintmod(root, p)), p, 0);
+ GEN e1 = ellinit(ellfromj(mkintmod(root, p)), p, 0);
pari_CATCH(e_TYPE) { continue; }
- pari_TRY { checkell(e); };
+ pari_TRY { checkell(e1); };
pari_ENDCATCH{};
+ debug_log("ellinit done");
- if (ord_prime) {
- // Easy part, the requested order is prime so
- // [order]G = 0 iff the curve has exactly order points, for any G on
- // it. otherwise it is the twist
- GEN g = genrand(e);
- if (ell_is_inf(ellmul(e, g, order))) {
- debug_log("Got curve.");
- return gerepilecopy(ltop, e);
- } else {
- debug_log("Got curve twist.");
- return gerepilecopy(ltop, ellinit(elltwist(e, NULL), p, 0));
- }
+ GEN ord = ellff_get_card(e1);
+ if (equalii(ord, order)) {
+ return gerepilecopy(ltop, e1);
} else {
- // Hard part, requested order is composite, so it might share a
- // factor with the order of the twist, which means [order]G = 0
- // might be true for a point on the twist as well as a point o the
- // right curve.
- //
- // We calculate what the twist order is, then compute gcd of the
- // orders which leads to the product of the factors that the orders
- // do not share. By multiplying a random point by this product on
- // some curve, we can determine that that curve has that number of
- // points.
- GEN twist_order = subii(addis(p, 1), subii(order, addis(p, 1)));
- GEN twist = ellinit(elltwist(e, NULL), p, 0);
- GEN gcd = gcdii(order, twist_order);
- GEN orig_mul = divii(order, gcd);
- GEN twist_mul = divii(twist_order, gcd);
- while (true) {
- GEN orig_point = genrand(e);
- if (ell_is_inf(ellmul(e, orig_point, orig_mul))) {
- debug_log("Got curve.");
- return gerepilecopy(ltop, e);
- }
- if (ell_is_inf(ellmul(e, orig_point, twist_mul))) {
- debug_log("Got curve twist.");
- return gerepilecopy(ltop, twist);
- }
- GEN twist_point = genrand(twist);
- if (ell_is_inf(ellmul(e, twist_point, twist_mul))) {
- debug_log("Got curve.");
- return gerepilecopy(ltop, e);
- }
- if (ell_is_inf(ellmul(e, twist_point, orig_mul))) {
- debug_log("Got curve twist.");
- return gerepilecopy(ltop, twist);
- }
- }
+ GEN e2 = ellinit(elltwist(e1, NULL), p, 0);
+ return gerepilecopy(ltop, e2);
}
}
avma = ltop;
return NULL;
}
-GEN cm_construct_curve_subgroup(GEN r, GEN d, GEN p) {
- debug_log("Constructing a curve with r = %Pi, d = %Pi, p = %Pi", r, d,
- p);
+GEN cm_construct_curve_subgroup(GEN r, GEN d, GEN p, cm_any_roots_t *roots) {
+ debug_log("Constructing a curve with r = %Pi, d = %Pi, p = %Pi", r, d, p);
pari_sp ltop = avma;
- GEN H = polclass(d, 0, 0);
- debug_log("H = %Ps", H);
- GEN roots = FpX_roots(H, p);
- debug_log("roots = %Ps", roots);
- if (gequal(roots, gtovec(gen_0))) {
+ debug_log("roots(%li/%li) = %Ps", roots->used, roots->total, roots->roots);
+ if (roots->total == 0 || roots->used == roots->total ||
+ gequal(roots->roots, gtovec(gen_0))) {
avma = ltop;
return NULL;
}
- long rlen = glength(roots);
pari_sp btop = avma;
- for (long i = 1; i <= rlen; ++i) {
- GEN root = gel(roots, i);
- debug_log("trying root = %Pi", root);
+ for (long i = roots->used; i < roots->total; ++i) {
+ roots->used = i + 1;
+ GEN root = gel(roots->roots, i + 1);
+ debug_log("trying root[%i] = %Pi", i + 1, root);
GEN e = ellinit(ellfromj(mkintmod(root, p)), p, 0);
- pari_CATCH(e_TYPE) { avma = btop; continue; }
+ pari_CATCH(e_TYPE) {
+ avma = btop;
+ continue;
+ }
pari_TRY { checkell(e); };
pari_ENDCATCH{};
@@ -247,21 +242,173 @@ GEN cm_construct_curve_subgroup(GEN r, GEN d, GEN p) {
return NULL;
}
+static cm_any_qdisc_t *min_d = NULL;
+static cm_any_roots_t *min_roots = NULL;
+static curve_t *min_curve = NULL;
+
GENERATOR(cm_gen_curve_any) {
HAS_ARG(args);
pari_sp ltop = avma;
const char *order_s = (const char *)args->args;
GEN order = strtoi(order_s);
- cm_any_qdisc_t min_disc = {0};
- good_qdisc_minimal(&min_disc, order);
- debug_log("Got min D = %Pi", min_disc.d);
- GEN e = cm_construct_curve(order, min_disc.d, min_disc.p, false);
+ GEN e;
+ if (min_d && min_roots && min_curve == curve &&
+ min_roots->used < min_roots->total) {
+ debug_log("Reusing roots.");
+ // We can just use the roots we have stored and take some out.
+ e = cm_construct_curve(order, min_d->d, min_d->p, min_roots, false);
+ } else if (min_d && min_curve == curve) {
+ debug_log("Reusing min D = %Pi", min_d->d);
+ // We just have the discriminant but no roots (or they are used up), we
+ // need to continue
+ if (min_d->d && isclone(min_d->d)) {
+ gunclone(min_d->d);
+ }
+ if (min_d->p && isclone(min_d->p)) {
+ gunclone(min_d->p);
+ }
+ good_qdisc_minimal(min_d, order);
+ min_d->d = gclone(min_d->d);
+ min_d->p = gclone(min_d->p);
+ debug_log("Got min D = %Pi", min_d->d);
+ if (min_roots) {
+ cm_update_roots(min_d->d, min_d->p, min_roots);
+ } else {
+ min_roots = cm_make_roots(min_d->d, min_d->p);
+ }
+ e = cm_construct_curve(order, min_d->d, min_d->p, min_roots, false);
+ } else {
+ // We have nothing. Start fresh.
+ debug_log("Fresh start.");
+ if (!min_d) {
+ min_d = try_calloc(sizeof(cm_any_qdisc_t));
+ }
+ if (min_d->d && isclone(min_d->d)) {
+ gunclone(min_d->d);
+ }
+ if (min_d->p && isclone(min_d->p)) {
+ gunclone(min_d->p);
+ }
+ good_qdisc_minimal(min_d, order);
+ min_d->d = gclone(min_d->d);
+ min_d->p = gclone(min_d->p);
+ debug_log("Got min D = %Pi", min_d->d);
+ min_roots = cm_make_roots(min_d->d, min_d->p);
+ min_curve = curve;
+ e = cm_construct_curve(order, min_d->d, min_d->p, min_roots, false);
+ }
+
+ if (e == NULL) {
+ debug_log("Could not construct curve.");
+ avma = ltop;
+ return -3;
+ }
+ curve->field = gcopy(min_d->p);
+ curve->a = ell_get_a4(e);
+ curve->b = ell_get_a6(e);
+ curve->curve = e;
+ return 1;
+}
+
+GENERATOR(cm_gen_curve_unique) {
+ HAS_ARG(args);
+ pari_sp ltop = avma;
+ const char *order_s = (const char *)args->args;
+ GEN order = strtoi(order_s);
+ GEN e;
+ if (min_d && min_curve == curve) {
+ debug_log("Reusing min D = %Pi", min_d->d);
+ // We have some discriminant, cannot use the roots because the D with
+ // walkdown was too large.
+ if (min_d->d && isclone(min_d->d)) {
+ gunclone(min_d->d);
+ }
+ if (min_d->p && isclone(min_d->p)) {
+ gunclone(min_d->p);
+ }
+ good_qdisc_minimal(min_d, order);
+ min_d->d = gclone(min_d->d);
+ min_d->p = gclone(min_d->p);
+ debug_log("Got min D = %Pi", min_d->d);
+ if (min_roots) {
+ cm_update_roots(min_d->d, min_d->p, min_roots);
+ } else {
+ min_roots = cm_make_roots(min_d->d, min_d->p);
+ }
+ e = cm_construct_curve(order, min_d->d, min_d->p, min_roots, false);
+ } else {
+ // We have nothing. Start fresh.
+ debug_log("Fresh start.");
+ if (!min_d) {
+ min_d = try_calloc(sizeof(cm_any_qdisc_t));
+ }
+ if (min_d->d && isclone(min_d->d)) {
+ gunclone(min_d->d);
+ }
+ if (min_d->p && isclone(min_d->p)) {
+ gunclone(min_d->p);
+ }
+ good_qdisc_minimal(min_d, order);
+ min_d->d = gclone(min_d->d);
+ min_d->p = gclone(min_d->p);
+ debug_log("Got min D = %Pi", min_d->d);
+ min_roots = cm_make_roots(min_d->d, min_d->p);
+ min_curve = curve;
+ e = cm_construct_curve(order, min_d->d, min_d->p, min_roots, false);
+ }
+
if (e == NULL) {
- fprintf(err, "Could not construct curve.");
+ debug_log("Could not construct curve.");
avma = ltop;
return -3;
}
- curve->field = min_disc.p;
+
+ GEN group = ellff_get_group(e);
+ long len = glength(group);
+ if (len == 2) {
+ pari_sp btop = avma;
+ debug_log("Walking down with structure %Ps.", group);
+ GEN d = gcopy(min_d->d);
+ GEN one = gel(group, 1);
+ GEN two = gel(group, 2);
+ GEN towalk = cmpii(one, two) < 0 ? one : two;
+ GEN factored = Z_factor(towalk);
+ GEN primes = gel(factored, 1);
+ GEN powers = gel(factored, 2);
+ for (long i = 1; i <= glength(primes); ++i) {
+ GEN prime = gel(primes, i);
+ GEN power = gel(powers, i);
+ debug_log("Walking down with %Pi^(2*%Pi)", prime, power);
+ GEN exp = mulis(power, 2);
+ GEN mul = powii(prime, exp);
+ debug_log("%Pi^%Pi = %Pi", prime, exp, mul);
+ d = mulii(d, mul);
+ debug_log("d = %Pi", d);
+ }
+ long dsize = logint(d, gen_2);
+ if (dsize > 30) {
+ debug_log(
+ "Discriminant too large after walkdown (d = %Pi, %li bits).", d,
+ dsize);
+ avma = ltop;
+ return -3;
+ }
+ if (min_roots) {
+ cm_update_roots(d, min_d->p, min_roots);
+ } else {
+ min_roots = cm_make_roots(d, min_d->p);
+ }
+ e = cm_construct_curve(order, d, min_d->p, min_roots, false);
+ e = gerepilecopy(btop, e);
+ }
+
+ if (e == NULL) {
+ debug_log("Could not construct curve.");
+ avma = ltop;
+ return -3;
+ }
+
+ curve->field = gcopy(min_d->p);
curve->a = ell_get_a4(e);
curve->b = ell_get_a6(e);
curve->curve = e;
@@ -273,4 +420,19 @@ GENERATOR(cm_gen_order) {
const char *order_s = (const char *)args->args;
curve->order = strtoi(order_s);
return 1;
-} \ No newline at end of file
+}
+
+void cm_any_quit(void) {
+ if (min_d) {
+ if (min_d->d && isclone(min_d->d)) {
+ gunclone(min_d->d);
+ }
+ if (min_d->p && isclone(min_d->p)) {
+ gunclone(min_d->p);
+ }
+ try_free(min_d);
+ }
+ if (min_roots) {
+ cm_free_roots(min_roots);
+ }
+}
diff --git a/src/cm/cm_any.h b/src/cm/cm_any.h
index a49fd7f..873b68f 100644
--- a/src/cm/cm_any.h
+++ b/src/cm/cm_any.h
@@ -12,22 +12,53 @@ typedef struct {
GEN d;
} cm_any_qdisc_t;
+typedef struct {
+ GEN roots;
+ long used;
+ long total;
+} cm_any_roots_t;
+
+/**
+ *
+ * @param d
+ * @param p
+ * @param roots
+ */
+void cm_update_roots(GEN d, GEN p, cm_any_roots_t *roots);
+
+/**
+ *
+ * @param d
+ * @param p
+ * @return
+ */
+cm_any_roots_t *cm_make_roots(GEN d, GEN p);
+
+void cm_free_roots(cm_any_roots_t *roots);
+
/**
* @brief Construct an elliptic curve given its order, CM discriminant and field
* order.
* @param order
* @param d
* @param p
+ * @param roots
* @param ord_prime
* @return
*/
-GEN cm_construct_curve(GEN order, GEN d, GEN p, bool ord_prime);
+GEN cm_construct_curve(GEN order, GEN d, GEN p, cm_any_roots_t *roots,
+ bool ord_prime);
/**
* @brief Construct an elliptic curve given a factor of its order, CM
* discriminant and field order.
+ *
+ * @param r
+ * @param d
+ * @param p
+ * @param roots
*/
-GEN cm_construct_curve_subgroup(GEN r, GEN d, GEN p);
+GEN cm_construct_curve_subgroup(GEN r, GEN d, GEN p, cm_any_roots_t *roots);
/**
* @brief
@@ -45,6 +76,20 @@ GENERATOR(cm_gen_curve_any);
* @param state
* @return
*/
+GENERATOR(cm_gen_curve_unique);
+
+/**
+ * @brief
+ * @param curve
+ * @param args
+ * @param state
+ * @return
+ */
GENERATOR(cm_gen_order);
+/**
+ * @brief Deinitialize.
+ */
+void cm_any_quit(void);
+
#endif // ECGEN_CM_ANY_H
diff --git a/src/cm/cm_prime.c b/src/cm/cm_prime.c
index 33d2a12..91c79c8 100644
--- a/src/cm/cm_prime.c
+++ b/src/cm/cm_prime.c
@@ -11,6 +11,11 @@
#include "obj/subgroup.h"
#include "util/bits.h"
+/*
+ * This file implements Algorithm 2.2 from
+ * "Constructing elliptic curves of prime order"
+ * https://pub.math.leidenuniv.nl/~stevenhagenp/bs.pdf
+ */
static size_t 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;
@@ -44,8 +49,9 @@ static size_t add_primes(GEN r, GEN order, GEN **primes, size_t nprimes) {
(*primes)[nprimes++] = pstar;
}
}
-
- *primes = try_realloc(*primes, sizeof(GEN) * nprimes);
+ if (nprimes) {
+ *primes = try_realloc(*primes, sizeof(GEN) * nprimes);
+ }
return nprimes;
}
@@ -75,60 +81,75 @@ static void qdisc_next(cm_prime_qdisc_t *qdisc) {
if (equalii(qdisc->i, imax) || qdisc->nprimes == 0) {
qdisc->nprimes =
add_primes(qdisc->r, qdisc->order, &(qdisc->Sp), qdisc->nprimes);
+ qdisc->i = gen_0;
imax = int2n(qdisc->nprimes);
}
pari_sp btop = avma;
while (true) {
- while (cmpii(qdisc->i, imax) < 0) {
+ debug_log("Primes:");
+ for (size_t j = 0; j < qdisc->nprimes; ++j) {
+ debug_log("%Pi", qdisc->Sp[j]);
+ }
+
+ GEN i = qdisc->i;
+ while (cmpii(i, imax) < 0) {
// debug_log("i %Pi", qdisc->i);
GEN pprod = gen_1;
- bits_t *ibits = bits_from_i_len(qdisc->i, qdisc->nprimes);
+ bits_t *ibits = bits_from_i_len(i, qdisc->nprimes);
+ char *b = bits_to_bin(ibits);
+ debug_log("bits: %s", b);
+ try_free(b);
for (size_t j = 0; j < qdisc->nprimes; ++j) {
if (GET_BIT(ibits->bits, j) == 1) {
- // debug_log("multiplying %Pi", qdisc->Sp[j]);
pprod = mulii(pprod, qdisc->Sp[j]);
}
}
bits_free(&ibits);
+ debug_log("pprod = %Pi, rlog^2 = %Pi, m8 = %Pi", pprod, rlog2,
+ modis(pprod, 8));
GEN absp = absi(pprod);
- long m4 = mod4(absp);
- if (cmpii(absp, rlog2) < 0 && equalii(modis(pprod, 8), stoi(5)) &&
- m4 != 1 && m4 != 2) {
+ // 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 = NULL;
GEN y = NULL;
+ // TODO: Check cornacchia -D vs +D
if (!cornacchia2(absp, qdisc->order, &x, &y)) {
- qdisc->i = gerepileupto(btop, addis(qdisc->i, 1));
- // debug_log("Cornacchia fail");
+ i = gerepileupto(btop, addis(i, 1));
+ debug_log("Cornacchia fail");
continue;
}
GEN pp1 = addii(addis(qdisc->order, 1), x);
GEN pp2 = subii(addis(qdisc->order, 1), x);
- if (isprime(pp1)) {
+ if (isprime(pp1) && cmpiu(pp1, 5) >= 0) {
qdisc->p = pp1;
qdisc->D = pprod;
qdisc->t = x;
- qdisc->i = addis(qdisc->i, 1);
+ qdisc->i = addis(i, 1);
debug_log("good D %Pi", pprod);
return;
}
- if (isprime(pp2)) {
+ if (isprime(pp2) && cmpiu(pp2, 5) >= 0) {
qdisc->p = pp2;
qdisc->D = pprod;
qdisc->t = x;
- qdisc->i = addis(qdisc->i, 1);
+ qdisc->i = addis(i, 1);
debug_log("good D %Pi", pprod);
return;
}
}
- qdisc->i = gerepileupto(btop, addis(qdisc->i, 1));
+ i = gerepileupto(btop, addis(i, 1));
}
+ // Another r loop
qdisc->r = addis(qdisc->r, 1);
qdisc->nprimes =
add_primes(qdisc->r, qdisc->order, &(qdisc->Sp), qdisc->nprimes);
+ qdisc->i = gen_0;
rlog2 = sqri(mulii(addis(qdisc->r, 1), logN));
imax = int2n(qdisc->nprimes);
@@ -146,15 +167,18 @@ GENERATOR(cm_gen_curve_prime) {
cm_prime_qdisc_t qdisc = {0};
qdisc_init(&qdisc, order);
+ cm_any_roots_t *roots = try_calloc(sizeof(cm_any_roots_t));
do {
qdisc_next(&qdisc);
- e = cm_construct_curve(order, qdisc.D, qdisc.p, true);
+ cm_update_roots(qdisc.D, qdisc.p, roots);
+ e = cm_construct_curve(order, qdisc.D, qdisc.p, roots, true);
} while (e == NULL);
qdisc_free(&qdisc);
+ cm_free_roots(roots);
curve->field = qdisc.p;
curve->a = ell_get_a4(e);
curve->b = ell_get_a6(e);
curve->curve = e;
return 1;
-} \ No newline at end of file
+}
diff --git a/src/cm/p1363.c b/src/cm/p1363.c
index fad2a05..90dcfd2 100644
--- a/src/cm/p1363.c
+++ b/src/cm/p1363.c
@@ -449,4 +449,4 @@ GEN p1363_polclass(GEN D) {
GEN WD = p1363_poly(D, forms, nforms);
p1363_free(&forms, nforms);
return gerepileupto(ltop, WD);
-} \ No newline at end of file
+}
diff --git a/src/ecgen.c b/src/ecgen.c
index 3c9b227..7e2074e 100644
--- a/src/ecgen.c
+++ b/src/ecgen.c
@@ -20,7 +20,7 @@
/**
* @file ecgen.c
* @author J08nY <johny@neuromancer.sk>
- * @version 0.7.7
+ * @version 0.8.2
* @copyright GPL v2.0
*/
#include <pari/pari.h>
@@ -38,11 +38,11 @@
#endif
const char *argp_program_version =
- "ecgen 0.7.7" GIT_VERSION
+ "ecgen 0.8.2" GIT_VERSION
"\n"
"Compiled with: " PARIVERSION
"\n\n"
- "Copyright (C) 2017-2018,2021,2024 J08nY\n"
+ "Copyright (C) 2017-2018,2021,2024,2025 J08nY\n"
"License GPLv2: GNU GPL version 2 (or later) "
"<http://gnu.org/licenses/gpl.html>\n"
"This is free software: you are free to change and redistribute it.\n"
@@ -67,6 +67,13 @@ bool init(void) {
default0("datadir", cfg->datadir);
}
+ // set threads limit for PARI
+ if (cfg->threads) {
+ char threads_s[30];
+ snprintf(threads_s, 30, "%lu", cfg->threads);
+ default0("nbthreads", threads_s);
+ }
+
#ifdef PARI_DEBUG
default0("debug", "2");
#endif
diff --git a/src/exhaustive/ansi.c b/src/exhaustive/ansi.c
index e369fb2..196a0a3 100644
--- a/src/exhaustive/ansi.c
+++ b/src/exhaustive/ansi.c
@@ -11,7 +11,7 @@
#include "util/memory.h"
#include "util/str.h"
-static seed_t *ansi_new() {
+static seed_t *ansi_new(void) {
seed_t *result = seed_new();
result->type = SEED_ANSI;
return result;
diff --git a/src/exhaustive/brainpool.c b/src/exhaustive/brainpool.c
index 56c095d..584ef5b 100644
--- a/src/exhaustive/brainpool.c
+++ b/src/exhaustive/brainpool.c
@@ -13,7 +13,7 @@
#include "util/bits.h"
#include "util/str.h"
-static seed_t *brainpool_new() {
+static seed_t *brainpool_new(void) {
seed_t *result = seed_new();
result->type = SEED_BRAINPOOL;
return result;
@@ -272,4 +272,4 @@ CHECK(brainpool_check_order) {
} else {
return -4;
}
-} \ No newline at end of file
+}
diff --git a/src/exhaustive/check.c b/src/exhaustive/check.c
index 5fa1c17..050b430 100644
--- a/src/exhaustive/check.c
+++ b/src/exhaustive/check.c
@@ -32,4 +32,4 @@ void check_free(check_t **check) {
try_free(*check);
*check = NULL;
}
-} \ No newline at end of file
+}
diff --git a/src/exhaustive/exhaustive.c b/src/exhaustive/exhaustive.c
index e8870f8..7833740 100644
--- a/src/exhaustive/exhaustive.c
+++ b/src/exhaustive/exhaustive.c
@@ -7,9 +7,8 @@
#include "arg.h"
#include "brainpool.h"
#include "brainpool_rfc.h"
-#include "nums.h"
-#include "family.h"
#include "check.h"
+#include "family.h"
#include "gen/curve.h"
#include "gen/equation.h"
#include "gen/field.h"
@@ -21,6 +20,7 @@
#include "gen/seed.h"
#include "io/output.h"
#include "misc/config.h"
+#include "nums.h"
#include "obj/curve.h"
#include "util/memory.h"
#include "util/timeout.h"
@@ -129,7 +129,8 @@ static void exhaustive_ginit(gen_f *generators) {
generators[OFFSET_SEED] = &gen_skip;
generators[OFFSET_FIELD] = &nums_gen_field;
generators[OFFSET_A] = &nums_gen_a;
- generators[OFFSET_B] = &nums_gen_b; // TODO: Missing transformation from b -> -b.
+ generators[OFFSET_B] =
+ &nums_gen_b; // TODO: Missing transformation from b -> -b.
generators[OFFSET_ORDER] = &nums_gen_order;
generators[OFFSET_GENERATORS] = &nums_gen_gens;
} break;
@@ -144,7 +145,6 @@ static void exhaustive_ginit(gen_f *generators) {
generators[OFFSET_SEED] = &family_gen_seed_random;
} else {
generators[OFFSET_SEED] = &family_gen_seed_input;
-
}
generators[OFFSET_FIELD] = &family_gen_field;
generators[OFFSET_A] = &gen_skip;
@@ -154,7 +154,7 @@ static void exhaustive_ginit(gen_f *generators) {
generators[OFFSET_B] = &family_gen_equation_iter;
}
- //TODO make the prime check optional, based on cfg->prime.
+ // TODO make the prime check optional, based on cfg->prime.
generators[OFFSET_ORDER] = &family_gen_order;
generators[OFFSET_GENERATORS] = &gens_gen_any;
} else {
@@ -487,7 +487,7 @@ int exhaustive_generate(exhaustive_t *setup) {
return result;
}
-int exhaustive_do() {
+int exhaustive_do(void) {
debug_log_start("Starting Exhaustive method");
gen_f generators[OFFSET_END] = {NULL};
diff --git a/src/exhaustive/exhaustive.h b/src/exhaustive/exhaustive.h
index 5abd03d..926836f 100644
--- a/src/exhaustive/exhaustive.h
+++ b/src/exhaustive/exhaustive.h
@@ -66,6 +66,6 @@ int exhaustive_generate(exhaustive_t *setup);
*
* @return
*/
-int exhaustive_do();
+int exhaustive_do(void);
#endif // ECGEN_EXHAUSTIVE_EXHAUSTIVE_H
diff --git a/src/exhaustive/family.c b/src/exhaustive/family.c
index 08505b6..2dcc24c 100644
--- a/src/exhaustive/family.c
+++ b/src/exhaustive/family.c
@@ -6,10 +6,10 @@
#include "family.h"
#include "cm/cm_any.h"
#include "gen/seed.h"
+#include "io/output.h"
#include "misc/config.h"
#include "util/bits.h"
#include "util/random.h"
-#include "io/output.h"
#define FAMILIES (FAMILY_KSS40 + 1)
@@ -20,7 +20,7 @@ static GEN tz_store[FAMILIES] = {0};
static GEN D_store[FAMILIES] = {0};
// clang-format off
-void family_init() {
+void family_init(void) {
pari_sp ltop = avma;
nz_store[FAMILY_BN] = gclone(closure_evalgen(compile_str("(z) -> z")));
pz_store[FAMILY_BN] = gclone(closure_evalgen(compile_str("(z) -> 36*z^4 + 36*z^3 + 24*z^2 + 6*z + 1")));
@@ -68,7 +68,7 @@ void family_init() {
}
// clang-format on
-static seed_t *family_new_seed() {
+static seed_t *family_new_seed(void) {
seed_t *result = seed_new();
result->type = SEED_FAMILY;
return result;
@@ -143,7 +143,9 @@ GENERATOR(family_gen_equation_cm) {
GEN n = closure_callgen1(nz_store[cfg->family], curve->seed->family.z);
GEN rz = closure_callgen1(rz_store[cfg->family], n);
GEN D = D_store[cfg->family];
- GEN e = cm_construct_curve_subgroup(rz, D, curve->field);
+ cm_any_roots_t *roots = cm_make_roots(D, curve->field);
+ GEN e = cm_construct_curve_subgroup(rz, D, curve->field, roots);
+ cm_free_roots(roots);
if (e) {
curve->a = ell_get_a4(e);
curve->b = ell_get_a6(e);
@@ -171,7 +173,7 @@ GENERATOR(family_gen_order) {
}
}
-void family_quit() {
+void family_quit(void) {
for (int i = 0; i < FAMILIES; i++) {
if (nz_store[i]) {
gunclone(nz_store[i]);
@@ -192,4 +194,4 @@ void family_quit() {
if (b) {
gunclone(b);
}
-} \ No newline at end of file
+}
diff --git a/src/exhaustive/family.h b/src/exhaustive/family.h
index 9b7deaa..5b398dc 100644
--- a/src/exhaustive/family.h
+++ b/src/exhaustive/family.h
@@ -22,9 +22,8 @@ GENERATOR(family_gen_equation_cm);
GENERATOR(family_gen_order);
-void family_init();
+void family_init(void);
-void family_quit();
+void family_quit(void);
-
-#endif //ECGEN_EXHAUSTIVE_FAMILY_H
+#endif // ECGEN_EXHAUSTIVE_FAMILY_H
diff --git a/src/exhaustive/nums.c b/src/exhaustive/nums.c
index 7e41938..1d3ae2a 100644
--- a/src/exhaustive/nums.c
+++ b/src/exhaustive/nums.c
@@ -22,7 +22,7 @@ GENERATOR(nums_gen_field) {
}
GENERATOR(nums_gen_a) {
- curve-> a = gmodulo(stoi(-3), curve->field);
+ curve->a = gmodulo(stoi(-3), curve->field);
return 1;
}
@@ -103,9 +103,8 @@ GENERATOR(nums_gen_gens) {
return 1;
}
-
void nums_quit(void) {
if (b && isclone(b)) {
gunclone(b);
}
-} \ No newline at end of file
+}
diff --git a/src/exhaustive/nums.h b/src/exhaustive/nums.h
index 40cb1b4..142f96a 100644
--- a/src/exhaustive/nums.h
+++ b/src/exhaustive/nums.h
@@ -55,6 +55,6 @@ GENERATOR(nums_gen_order);
*/
GENERATOR(nums_gen_gens);
-void nums_quit();
+void nums_quit(void);
#endif // ECGEN_EXHAUSTIVE_NUMS_H
diff --git a/src/gen/gens.c b/src/gen/gens.c
index a743e79..329149a 100644
--- a/src/gen/gens.c
+++ b/src/gen/gens.c
@@ -5,9 +5,9 @@
#include "gens.h"
#include "exhaustive/arg.h"
#include "math/subgroup.h"
+#include "misc/compat.h"
#include "obj/point.h"
#include "obj/subgroup.h"
-#include "misc/compat.h"
static subgroup_t *gens_point(GEN point, const curve_t *curve) {
subgroup_t *sub = subgroup_new();
@@ -37,13 +37,20 @@ GENERATOR(gens_gen_any) {
GENERATOR(gens_gen_one) {
pari_sp ltop = avma;
+ GEN group = ellff_get_group(curve->curve);
+ debug_log("Group structure %Ps.", group);
+ long len = glength(group);
+ if (len == 2) {
+ avma = ltop;
+ return -5;
+ }
GEN generators = ellff_get_gens(curve->curve);
- long len = glength(generators);
+ len = glength(generators);
if (len == 2) {
avma = ltop;
return -5;
}
- return gens_put(curve, generators, len);
+ return gens_put(curve, gerepilecopy(ltop, generators), len);
}
GENERATOR(gens_gen_cofactor) {
diff --git a/src/gen/hex.c b/src/gen/hex.c
index 58250a0..559e86c 100644
--- a/src/gen/hex.c
+++ b/src/gen/hex.c
@@ -121,4 +121,4 @@ CHECK(hex_check_param) {
}
try_free(search_hex);
return result;
-} \ No newline at end of file
+}
diff --git a/src/gen/metadata.c b/src/gen/metadata.c
index b857ec7..7d455ef 100644
--- a/src/gen/metadata.c
+++ b/src/gen/metadata.c
@@ -28,7 +28,8 @@ GENERATOR(metadata_gen) {
GEN d_f = coredisc2(subii(sqri(frobenius), mulis(q, 4)));
cm_disc = gcopy(gel(d_f, 1));
conductor = gcopy(gel(d_f, 2));
- gerepileall(ltop, 6, &j, &disc, &embedding_degree, &frobenius, &cm_disc, &conductor);
+ gerepileall(ltop, 6, &j, &disc, &embedding_degree, &frobenius, &cm_disc,
+ &conductor);
} else if (typ(curve->field) == t_FFELT) {
cm_disc = NULL;
conductor = NULL;
diff --git a/src/gen/order.c b/src/gen/order.c
index a9d22b2..64ef665 100644
--- a/src/gen/order.c
+++ b/src/gen/order.c
@@ -158,4 +158,4 @@ CHECK(order_check_discriminant) {
}
avma = ltop;
return 1;
-} \ No newline at end of file
+}
diff --git a/src/invalid/invalid.c b/src/invalid/invalid.c
index 3679c6b..6742148 100644
--- a/src/invalid/invalid.c
+++ b/src/invalid/invalid.c
@@ -289,8 +289,7 @@ static size_t invalid_curves_threaded(const curve_t *curve, pari_ulong *primes,
}
}
- if (*generated == nprimes)
- break;
+ if (*generated == nprimes) break;
}
pthread_mutex_unlock(&state_mutex);
@@ -328,7 +327,7 @@ curve_t *invalid_original_curve(exhaustive_t *setup) {
return curve;
}
-int invalid_do() {
+int invalid_do(void) {
debug_log_start("Starting Invalid curve method");
gen_f original_gens[OFFSET_END] = {NULL};
diff --git a/src/invalid/invalid.h b/src/invalid/invalid.h
index 15d6441..41bea15 100644
--- a/src/invalid/invalid.h
+++ b/src/invalid/invalid.h
@@ -14,6 +14,6 @@
*
* @return
*/
-int invalid_do();
+int invalid_do(void);
#endif // ECGEN_INVALID_INVALID_H
diff --git a/src/io/cli.c b/src/io/cli.c
index d98a0c0..65524c9 100644
--- a/src/io/cli.c
+++ b/src/io/cli.c
@@ -88,7 +88,7 @@ struct argp_option cli_options[] = {
{0, 0, 0, 0, "Other:", 5},
{"data-dir", OPT_DATADIR, "DIR", 0, "Set PARI/GP data directory (containing seadata package).", 5},
{"memory", OPT_MEMORY, "SIZE", 0, "Use PARI stack of SIZE (can have suffix k/m/g).", 5},
- {"threads", OPT_THREADS, "NUM", 0, "Use NUM threads.", 5},
+ {"threads", OPT_THREADS, "NUM", 0, "Use NUM threads (in PARI or invalid generation).", 5},
{"thread-stack", OPT_TSTACK, "SIZE", 0, "Use PARI stack of SIZE (per thread, can have suffix k/m/g).", 5},
{"timeout", OPT_TIMEOUT, "TIME", 0, "Timeout computation of a curve parameter after TIME (can have suffix s/m/h/d).", 5},
{0}
@@ -97,7 +97,7 @@ struct argp_option cli_options[] = {
static regex_t re_cm_order;
-bool cli_init() {
+bool cli_init(void) {
int error = regcomp(
&re_cm_order,
"((0[xX][0-9a-fA-F]+)|([0-9]+))(,((0[xX][0-9a-fA-F]+)|([0-9]+)))*",
@@ -540,4 +540,4 @@ char *cli_filter(int key, const char *text, void *input) {
return (char *)text;
}
-void cli_quit() { regfree(&re_cm_order); }
+void cli_quit(void) { regfree(&re_cm_order); }
diff --git a/src/io/cli.h b/src/io/cli.h
index abeb6e6..a712c44 100644
--- a/src/io/cli.h
+++ b/src/io/cli.h
@@ -19,7 +19,7 @@ extern struct argp_option cli_options[];
/**
* @brief
*/
-bool cli_init();
+bool cli_init(void);
/**
* @brief
@@ -42,6 +42,6 @@ char *cli_filter(int key, const char *text, void *input);
/**
*
*/
-void cli_quit();
+void cli_quit(void);
#endif // ECGEN_IO_CLI_H
diff --git a/src/io/input.c b/src/io/input.c
index 507bd59..4c23c28 100644
--- a/src/io/input.c
+++ b/src/io/input.c
@@ -93,7 +93,7 @@ GEN input_string(const char *prompt) {
return result;
}
-bool input_init() {
+bool input_init(void) {
if (cfg->input) {
in = fopen(cfg->input, "r");
delim = ',';
diff --git a/src/io/input.h b/src/io/input.h
index a56347a..c1ac88e 100644
--- a/src/io/input.h
+++ b/src/io/input.h
@@ -50,7 +50,7 @@ extern FILE *in;
* @brief Initialize input based on cfg.
* @return whether the initialization was successful
*/
-bool input_init();
+bool input_init(void);
/**
* @brief Deinitialize input.
diff --git a/src/io/output.c b/src/io/output.c
index c4704c1..a625446 100644
--- a/src/io/output.c
+++ b/src/io/output.c
@@ -10,9 +10,9 @@
#include "util/memory.h"
char *(*output_s)(curve_t *curve);
-char *(*output_s_separator)();
-char *(*output_s_begin)();
-char *(*output_s_end)();
+char *(*output_s_separator)(void);
+char *(*output_s_begin)(void);
+char *(*output_s_end)(void);
FILE *out;
FILE *err;
@@ -165,8 +165,7 @@ static JSON_Value *output_jjson(curve_t *curve) {
}
if (curve->meta.conductor != NULL) {
char *conductor = pari_sprintf("%Pi", curve->meta.conductor);
- json_object_dotset_string(root_object, "meta.conductor",
- conductor);
+ json_object_dotset_string(root_object, "meta.conductor", conductor);
pari_free(conductor);
}
}
@@ -183,11 +182,11 @@ char *output_sjson(curve_t *curve) {
return result;
}
-char *output_sjson_separator() { return output_malloc(",\n"); }
+char *output_sjson_separator(void) { return output_malloc(",\n"); }
-char *output_sjson_begin() { return output_malloc("[\n"); }
+char *output_sjson_begin(void) { return output_malloc("[\n"); }
-char *output_sjson_end() { return output_malloc("]\n"); }
+char *output_sjson_end(void) { return output_malloc("]\n"); }
void output_f(FILE *output, curve_t *curve) {
char *s = output_s(curve);
@@ -207,7 +206,7 @@ void output_f_separator(FILE *output) {
}
}
-void output_o_separator() { output_f_separator(out); }
+void output_o_separator(void) { output_f_separator(out); }
void output_f_begin(FILE *output) {
char *s = output_s_begin();
@@ -217,7 +216,7 @@ void output_f_begin(FILE *output) {
}
}
-void output_o_begin() { output_f_begin(out); }
+void output_o_begin(void) { output_f_begin(out); }
void output_f_end(FILE *output) {
char *s = output_s_end();
@@ -227,9 +226,9 @@ void output_f_end(FILE *output) {
}
}
-void output_o_end() { output_f_end(out); }
+void output_o_end(void) { output_f_end(out); }
-bool output_init() {
+bool output_init(void) {
json_set_allocation_functions(try_malloc, try_free);
if (cfg->output) {
diff --git a/src/io/output.h b/src/io/output.h
index f68acfc..477def4 100644
--- a/src/io/output.h
+++ b/src/io/output.h
@@ -89,21 +89,21 @@ char *output_sjson(curve_t *curve);
* format.
* @return
*/
-char *output_sjson_separator();
+char *output_sjson_separator(void);
/**
* @brief Output JSON output header(a "[") to a malloc'ed string in CSV
* format.
* @return
*/
-char *output_sjson_begin();
+char *output_sjson_begin(void);
/**
* @brief Output JSON output footer(a "]") to a malloc'ed string in CSV
* format.
* @return
*/
-char *output_sjson_end();
+char *output_sjson_end(void);
/**
* @brief Output curve to a malloc'ed string in configured format.
@@ -129,7 +129,7 @@ void output_o(curve_t *curve);
* @brief Output separator to a malloc'ed string in configured format.
* @return
*/
-extern char *(*output_s_separator)();
+extern char *(*output_s_separator)(void);
/**
* @brief Output separator to a FILE *out in configured format.
@@ -140,13 +140,13 @@ void output_f_separator(FILE *out);
/**
* @brief Output separator to configured output in configured format.
*/
-void output_o_separator();
+void output_o_separator(void);
/**
* @brief Output header to a malloc'ed string in configured format.
* @return
*/
-extern char *(*output_s_begin)();
+extern char *(*output_s_begin)(void);
/**
* @brief Output header to a FILE *out in configured format.
@@ -157,13 +157,13 @@ void output_f_begin(FILE *out);
/**
* @brief Output header to configured output in configured format.
*/
-void output_o_begin();
+void output_o_begin(void);
/**
* @brief Output footer to a malloc'ed string in configured format.
* @return
*/
-extern char *(*output_s_end)();
+extern char *(*output_s_end)(void);
/**
* @brief Output footer to a FILE *out in configured format.
@@ -174,7 +174,7 @@ void output_f_end(FILE *out);
/**
* @brief Output header to configured output in configured format.
*/
-void output_o_end();
+void output_o_end(void);
/**
* @brief Configured output FILE*.
@@ -195,7 +195,7 @@ extern FILE *verbose;
* @brief Initialize output based on cfg.
* @return whether the initialization was successful
*/
-bool output_init();
+bool output_init(void);
/**
* @brief Deinitialize output.
diff --git a/src/math/koblitz.c b/src/math/koblitz.c
index ca91160..903b4f7 100644
--- a/src/math/koblitz.c
+++ b/src/math/koblitz.c
@@ -70,4 +70,4 @@ GEN koblitz_get_order(unsigned long m, unsigned long a) {
} else {
return NULL;
}
-} \ No newline at end of file
+}
diff --git a/src/math/subgroup.c b/src/math/subgroup.c
index fdf45a5..cdf7acb 100644
--- a/src/math/subgroup.c
+++ b/src/math/subgroup.c
@@ -3,6 +3,7 @@
* Copyright (C) 2017-2018 J08nY
*/
#include "subgroup.h"
+#include "io/output.h"
/**
* @brief All prime divisors of a given integer with multiplicity.
@@ -46,6 +47,11 @@ static GEN subgroups_2n_factors(GEN factors, size_t min_bits) {
long nprimes = glength(factors);
if (nprimes == min_bits) return NULL;
GEN amount = int2n(nprimes);
+ long abits = logint(amount, gen_2);
+ if (abits >= 64) {
+ fprintf(err, "Too many factors to generate points (%li bits).", abits);
+ return NULL;
+ }
GEN groups = gtovec0(gen_0, itos(amount) - (min_bits * nprimes) - 1);
size_t i = 0;
@@ -140,4 +146,4 @@ static GEN subgroups_2n(const curve_t *curve, size_t min_bits) {
return subgroups_2n_gens(curve, min_bits);
}
-*/ \ No newline at end of file
+*/
diff --git a/src/math/twists.c b/src/math/twists.c
index 0d4b14c..a4ae2b9 100644
--- a/src/math/twists.c
+++ b/src/math/twists.c
@@ -33,4 +33,4 @@ void twist_rand(curve_t *what) {
twist_rand_to(what, what);
seed_free(&what->seed);
subgroups_free_deep(&what->generators, what->ngens);
-} \ No newline at end of file
+}
diff --git a/src/misc/compat.h b/src/misc/compat.h
index 7e3d4e8..ccacb2e 100644
--- a/src/misc/compat.h
+++ b/src/misc/compat.h
@@ -12,17 +12,24 @@
#define PARI_VERSION_MINOR (((PARI_VERSION_CODE) >> 8) & 0xff)
#define PARI_VERSION_MAJOR (PARI_VERSION_CODE >> 16)
-#define PARI_VERSION_GT(a,b,c) ((PARI_VERSION_MAJOR == a && PARI_VERSION_MINOR == b && PARI_VERSION_PATCH > c) || (PARI_VERSION_MAJOR == a && PARI_VERSION_MINOR > b) || (PARI_VERSION_MAJOR > a))
-#define PARI_VERSION_EQ(a,b,c) (PARI_VERSION_MAJOR == a && PARI_VERSION_MINOR == b && PARI_VERSION_PATCH == c)
-#define PARI_VERSION_GE(a,b,c) (PARI_VERSION_GT(a,b,c) || PARI_VERSION_EQ(a,b,c))
-#define PARI_VERSION_LT(a,b,c) !(PARI_VERSION_GE(a,b,c))
-#define PARI_VERSION_LE(a,b,c) !(PARI_VERSION_GT(a,b,c))
+#define PARI_VERSION_GT(a, b, c) \
+ ((PARI_VERSION_MAJOR == a && PARI_VERSION_MINOR == b && \
+ PARI_VERSION_PATCH > c) || \
+ (PARI_VERSION_MAJOR == a && PARI_VERSION_MINOR > b) || \
+ (PARI_VERSION_MAJOR > a))
+#define PARI_VERSION_EQ(a, b, c) \
+ (PARI_VERSION_MAJOR == a && PARI_VERSION_MINOR == b && \
+ PARI_VERSION_PATCH == c)
+#define PARI_VERSION_GE(a, b, c) \
+ (PARI_VERSION_GT(a, b, c) || PARI_VERSION_EQ(a, b, c))
+#define PARI_VERSION_LT(a, b, c) !(PARI_VERSION_GE(a, b, c))
+#define PARI_VERSION_LE(a, b, c) !(PARI_VERSION_GT(a, b, c))
-#if PARI_VERSION_LT(2,12,1)
+#if PARI_VERSION_LT(2, 12, 1)
#define polisirreducible isirreducible
#endif
-#if PARI_VERSION_LT(2,15,0)
+#if PARI_VERSION_LT(2, 15, 0)
#define znorder(x, o) order(x);
#endif
diff --git a/src/misc/config.c b/src/misc/config.c
index 155cbb4..9f66b51 100644
--- a/src/misc/config.c
+++ b/src/misc/config.c
@@ -15,7 +15,7 @@ config_names_t *cfg_used = &cfg_used_s;
config_names_t cfg_set_s = {0};
config_names_t *cfg_set = &cfg_set_s;
-void config_report_unused() {
+void config_report_unused(void) {
bool unused = false;
if (cfg_set->field && !cfg_used->field) {
fprintf(
@@ -120,4 +120,4 @@ void config_report_unused() {
#else
(void)unused;
#endif
-} \ No newline at end of file
+}
diff --git a/src/misc/config.h b/src/misc/config.h
index 3272190..b4fbc79 100644
--- a/src/misc/config.h
+++ b/src/misc/config.h
@@ -129,7 +129,7 @@ typedef struct {
char *datadir;
/** @brief How much memory to allocate for the PARI stack. */
unsigned long memory;
- /** @brief How many threads to use, only useful for invalid generation(atm).
+ /** @brief How many threads to use (or limit PARI to use).
*/
unsigned long threads;
/** @brief How much memory to allocate for the PARI stack, per thread. */
@@ -191,6 +191,6 @@ extern config_names_t *cfg_set;
#define GET_BOOL(x) ((cfg_used->x = true) && cfg->x)
#define SET(x) cfg_set->x = true
-void config_report_unused();
+void config_report_unused(void);
#endif // ECGEN_MISC_CONFIG_H
diff --git a/src/obj/curve.c b/src/obj/curve.c
index 4821442..10b720e 100644
--- a/src/obj/curve.c
+++ b/src/obj/curve.c
@@ -62,4 +62,4 @@ void curve_free(curve_t **curve) {
try_free(*curve);
*curve = NULL;
}
-} \ No newline at end of file
+}
diff --git a/src/obj/obj.h b/src/obj/obj.h
index 5a7f9ab..86a8d1d 100644
--- a/src/obj/obj.h
+++ b/src/obj/obj.h
@@ -5,15 +5,15 @@
#include "misc/types.h"
#include "util/memory.h"
-#define OBJ(obj_name, obj_type, copy_func, clone_func) \
- obj_type *obj_name##_new() { return try_calloc(sizeof(obj_type)); } \
- obj_type *obj_name##_new_copy(const obj_type *src) { \
- obj_type *result = obj_name##_new(); \
- return copy_func(src, result); \
- } \
- obj_type *obj_name##_new_clone(const obj_type *src) { \
- obj_type *result = obj_name##_new(); \
- return clone_func(src, result); \
+#define OBJ(obj_name, obj_type, copy_func, clone_func) \
+ obj_type *obj_name##_new(void) { return try_calloc(sizeof(obj_type)); } \
+ obj_type *obj_name##_new_copy(const obj_type *src) { \
+ obj_type *result = obj_name##_new(); \
+ return copy_func(src, result); \
+ } \
+ obj_type *obj_name##_new_clone(const obj_type *src) { \
+ obj_type *result = obj_name##_new(); \
+ return clone_func(src, result); \
}
#define OBJS(obj_name, obj_type, copy_func, clone_func) \
@@ -44,7 +44,7 @@
}
#define OBJ_H(obj_name, obj_type) \
- obj_type *obj_name##_new(); \
+ obj_type *obj_name##_new(void); \
obj_type *obj_name##_new_copy(const obj_type *src); \
obj_type *obj_name##_new_clone(const obj_type *src);
diff --git a/src/obj/point.c b/src/obj/point.c
index 2b709dd..4722bad 100644
--- a/src/obj/point.c
+++ b/src/obj/point.c
@@ -48,4 +48,4 @@ void points_free_deep(point_t ***points, unsigned long npoints) {
}
points_free(points);
}
-} \ No newline at end of file
+}
diff --git a/src/util/bits.c b/src/util/bits.c
index 0d60c26..b73a55d 100644
--- a/src/util/bits.c
+++ b/src/util/bits.c
@@ -174,16 +174,18 @@ char *bits_to_hex(const bits_t *bits) {
// else
// 0 0 | a b | c d | e
// ^-----^ (8-offset zero bits, offset bits from first byte)
- // ^-----^ (8-offset bits from first byte, offset bits from second byte)
+ // ^-----^ (8-offset bits from first byte, offset bits from second
+ // byte)
// ....
- // ^-----^ (8-offset bits from second to last byte, offset bits from last byte)
+ // ^-----^ (8-offset bits from second to last byte, offset bits
+ // from last byte)
for (size_t i = 0; i < BYTE_LEN(bits->bitlen); ++i) {
size_t pos = (i * 2) + (bits->sign ? 1 : 0);
unsigned char value;
if (offset) {
value = bits->bits[i] >> (8 - offset);
if (i != 0) {
- value |= (bits->bits[i-1] & ~(1 << (8 - offset))) << offset;
+ value |= (bits->bits[i - 1] & ~(1 << (8 - offset))) << offset;
}
} else {
value = bits->bits[i];
diff --git a/src/util/memory.c b/src/util/memory.c
index f05efae..b84a4c4 100644
--- a/src/util/memory.c
+++ b/src/util/memory.c
@@ -72,4 +72,4 @@ void set_mem_funcs(void *(*malloc_fun)(size_t), void *(*calloc_fun)(size_t),
calloc_func = calloc_fun;
realloc_func = realloc_fun;
free_func = free_fun;
-} \ No newline at end of file
+}
diff --git a/src/util/random.c b/src/util/random.c
index b88bb50..844e0f6 100644
--- a/src/util/random.c
+++ b/src/util/random.c
@@ -5,8 +5,8 @@
#define _POSIX_C_SOURCE 200809L
#include "random.h"
-#include <time.h>
#include <stdint.h>
+#include <time.h>
void random_reseed(void) {
pari_ulong seed = 0;
@@ -15,7 +15,8 @@ void random_reseed(void) {
if (rand) {
size_t read = 0;
while (read < sizeof(pari_ulong)) {
- read += fread(((uint8_t*) &seed) + read, 1, sizeof(pari_ulong) - read, rand);
+ read += fread(((uint8_t *)&seed) + read, 1,
+ sizeof(pari_ulong) - read, rand);
}
fclose(rand);
diff --git a/src/util/str.c b/src/util/str.c
index ff075f2..ade97a9 100644
--- a/src/util/str.c
+++ b/src/util/str.c
@@ -68,7 +68,6 @@ char *str_concat(char **strings, size_t len) {
size_t str_cnt(const char *str, const char c) {
size_t result = 0;
- for (; str[result]; str[result] == c ? result++ : *str++)
- ;
+ for (; str[result]; str[result] == c ? result++ : *str++);
return result;
}
diff --git a/src/util/timeout.c b/src/util/timeout.c
index 6fdbf16..5cfa552 100644
--- a/src/util/timeout.c
+++ b/src/util/timeout.c
@@ -19,17 +19,17 @@ void timeout_handle(int signum, siginfo_t *siginfo, void *other) {
if (timeout_in) siglongjmp(timeout_ptr, 1);
}
-void timeout_thread_init() {
+void timeout_thread_init(void) {
timeout_timer = try_calloc(sizeof(timer_t));
sevp = try_calloc(sizeof(struct sigevent));
}
-void timeout_thread_quit() {
+void timeout_thread_quit(void) {
try_free(timeout_timer);
try_free(sevp);
}
-bool timeout_init() {
+bool timeout_init(void) {
// init for the main thread.
timeout_thread_init();
struct sigaction new_action;
@@ -42,7 +42,7 @@ bool timeout_init() {
return true;
}
-void timeout_quit() {
+void timeout_quit(void) {
// deinit the main thread.
timeout_thread_quit();
}
diff --git a/src/util/timeout.h b/src/util/timeout.h
index 57e3d22..6f6805b 100644
--- a/src/util/timeout.h
+++ b/src/util/timeout.h
@@ -69,19 +69,19 @@ extern __thread struct sigevent *sevp;
} \
}
-void timeout_thread_init();
+void timeout_thread_init(void);
-void timeout_thread_quit();
+void timeout_thread_quit(void);
/**
* @brief Initialize the timeout system.
* @return whether the initalization was successful
*/
-bool timeout_init();
+bool timeout_init(void);
/**
* @brief Deinitialize the timeout system.
*/
-void timeout_quit();
+void timeout_quit(void);
#endif // ECGEN_UTIL_TIMEOUT_H
diff --git a/test/common.sh b/test/common.sh
index 42978a3..7d1ea22 100644
--- a/test/common.sh
+++ b/test/common.sh
@@ -7,7 +7,6 @@
####
ecgen="../ecgen"
-econvert="../econvert"
ASSERT="lib/assert.sh/assert.sh"
JSON="lib/JSON.sh/JSON.sh"
@@ -41,3 +40,10 @@ canonical_num() {
num=$(strip_num "$1")
echo "ibase=16;${num^^}" | bc
}
+
+get_pari_order() {
+ p=$(canonical_num $(echo $1 | ${JSON} -x field\",\"p | cut -f 2))
+ a=$(canonical_num $(echo $1 | ${JSON} -x \"a | cut -f 2))
+ b=$(canonical_num $(echo $1 | ${JSON} -x \"b | cut -f 2))
+ echo "ellcard(ellinit([${a}, ${b}], ${p}))" | gp -f -q | tr -cd [:digit:] 2>/dev/null
+} \ No newline at end of file
diff --git a/test/ecgen.sh b/test/ecgen.sh
index 38670bc..96dacb3 100755
--- a/test/ecgen.sh
+++ b/test/ecgen.sh
@@ -101,20 +101,24 @@ function nums() {
function anomalous() {
start_test
assert_raises "${ecgen} --fp --anomalous -r 20"
- out=$(${ecgen} --fp --anomalous -r 20 2>/dev/null)
- p=$(echo $out | ${JSON} -x field\",\"p | cut -f 2)
- order=$(echo $out | ${JSON} -x ^0,\"order\" | cut -f 2)
- assert "strip_num $p" $(strip_num $order)
+ for i in $(seq 10); do
+ out=$(${ecgen} --fp --anomalous -r 20 2>/dev/null)
+ p=$(echo $out | ${JSON} -x field\",\"p | cut -f 2)
+ order=$(echo $out | ${JSON} -x ^0,\"order\" | cut -f 2)
+ assert "strip_num $p" $(strip_num $order)
+ done
}
function supersingular() {
start_test
assert_raises "${ecgen} --fp --supersingular -r -c 5 20"
- out=$(${ecgen} --fp --supersingular -r 20 2>/dev/null)
- p=$(echo $out | ${JSON} -x field\",\"p | cut -f 2)
- order=$(echo $out | ${JSON} -x ^0,\"order\" | cut -f 2)
- order_m1=$(echo $(canonical_num $order) - 1 | bc)
- assert "canonical_num $p" $order_m1
+ for i in $(seq 10); do
+ out=$(${ecgen} --fp --supersingular -r 20 2>/dev/null)
+ p=$(echo $out | ${JSON} -x field\",\"p | cut -f 2)
+ order=$(echo $out | ${JSON} -x ^0,\"order\" | cut -f 2)
+ order_m1=$(echo $(canonical_num $order) - 1 | bc)
+ assert "canonical_num $p" $order_m1
+ done
assert_raises "${ecgen} --fp --supersingular --input=data/prime.in 64"
@@ -187,12 +191,42 @@ function hex() {
function cm() {
start_test
assert_raises "${ecgen} --fp --order=2147483723 32"
- assert_raises "${ecgen} --fp --order=123456789012345678901234567890123456789012345678901234568197 196"
+ assert_raises "${ecgen} --fp --order=123456789012345678901234567890123456789012345678901234568197 --threads=5 196"
assert_raises "${ecgen} --fp --order=46874566546,3546,3125 64"
+ assert_raises "${ecgen} --fp -u --order=46874566546,3546,3125 64"
assert_raises "${ecgen} --fp --order=0 16" 1
assert_raises "${ecgen} --fp --order=0x1000 8" 1
}
+function cm_orders() {
+ start_test
+ for i in $(seq 5 100); do
+ out=$(timeout -k 4 3 ${ecgen} --fp -n $i --points=none 6 2>/dev/null)
+ if [[ -z "$out" || "$out" = "[" ]]; then
+ continue
+ fi
+ order=$(echo $out | ${JSON} -x ^0,\"order\" | cut -f 2)
+ pari_order=$(get_pari_order "$out")
+ assert "canonical_num $order" "$pari_order"
+ done
+
+ prime_orders=(45678945611413 47889465415131 78246132456157 3879641663983 134537095890397 3790687732807)
+ for ord in "${prime_orders[@]}"; do
+ out=$(${ecgen} --fp -r --order=$ord 64 2>/dev/null)
+ p=$(echo $out | ${JSON} -x field\",\"p | cut -f 2)
+ order=$(echo $out | ${JSON} -x ^0,\"order\" | cut -f 2)
+ assert "canonical_num $order" $ord
+ done
+
+ composite_orders=(106618070007935 32268705670290 78286235471710 93953327960423 17042092126557 43615536370894)
+ for ord in "${composite_orders[@]}"; do
+ out=$(${ecgen} --fp -r --order=$ord 64 2>/dev/null)
+ p=$(echo $out | ${JSON} -x field\",\"p | cut -f 2)
+ order=$(echo $out | ${JSON} -x ^0,\"order\" | cut -f 2)
+ assert "canonical_num $order" $ord
+ done
+}
+
function secg() {
function test_order() {
name="${1}"
@@ -235,5 +269,6 @@ twist
cli
hex
cm
+cm_orders
secg
end_suite ecgen
diff --git a/test/src/util/test_bits.c b/test/src/util/test_bits.c
index 269d1f6..e5a2f73 100644
--- a/test/src/util/test_bits.c
+++ b/test/src/util/test_bits.c
@@ -243,14 +243,14 @@ Test(bits, test_bits_or) {
bits_t *other_bits = bits_new(6);
other_bits->bits[0] = 0b10000000;
- bits_t * or = bits_or(bits, other_bits);
+ bits_t *or = bits_or(bits, other_bits);
cr_assert_not_null(or, );
cr_assert_eq(or->bitlen, 10, );
cr_assert_eq(or->bits[0], 0b00001000, );
cr_assert_eq(or->bits[1], 0b11000000, );
bits_free(&bits);
bits_free(&other_bits);
- bits_free(& or);
+ bits_free(&or);
}
Test(bits, test_bits_and) {