aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ08nY2024-11-30 00:18:22 +0100
committerJ08nY2024-11-30 00:18:22 +0100
commit8395408db3d707be8573203b07625175e005ef74 (patch)
tree70727f1940e074206c0675b8017ad13da3b9587d
parente1af97551fde2efbd847e872fbcde9380e24fe42 (diff)
downloadecgen-8395408db3d707be8573203b07625175e005ef74.tar.gz
ecgen-8395408db3d707be8573203b07625175e005ef74.tar.zst
ecgen-8395408db3d707be8573203b07625175e005ef74.zip
-rw-r--r--README.md18
-rw-r--r--docs/readme.md1
-rw-r--r--src/cm/cm.c21
-rw-r--r--src/exhaustive/exhaustive.c47
-rw-r--r--src/invalid/invalid.c7
-rw-r--r--src/io/cli.c31
-rw-r--r--src/misc/config.c91
-rw-r--r--src/misc/config.h32
8 files changed, 225 insertions, 23 deletions
diff --git a/README.md b/README.md
index 95fe949..eeeab77 100644
--- a/README.md
+++ b/README.md
@@ -184,6 +184,15 @@ Generate a prime field, uniquely generated random curve, of size 192 bits, also
}
}]
+
+> [!NOTE]
+> The command-line interface is quite tricky and **will** ignore options somewhat silently,
+> meaning that the computation will go on and some properties of the output curve will be wrong.
+>
+> If this happens, you will get a warning such as:
+> > Warning: Ignored command-line argument prime (-p/--prime).
+
+
### Docs
See [docs](docs/readme.md). Also:
@@ -236,11 +245,14 @@ Four different EC curve parameters generation methods are implemented.
#### Supersingular curves
+ - Generates curves of order equal to prime + 1 (trace of Frobenius equal to zero).
+ - Used with the `--supersingular` option.
+ - These curves are **NOT SECURE** and are useful for implementation testing.
- [CONSTRUCTING SUPERSINGULAR ELLIPTIC CURVES - [Broker]](https://pdfs.semanticscholar.org/56c5/5b9cf0b218f93b8d263cc9f64ccb5fb97f52.pdf)
#### Anomalous curve generation
- - Generates curves of order equal to field order.
+ - Generates curves of order equal to field order (trace of Frobenius equal to 1).
- Used with the `--anomalous` option.
- These curves are **NOT SECURE** and are useful for implementation testing.
- [Elliptic curves over F_p suitable for cryptosystems - [Miyaji]](https://dspace.jaist.ac.jp/dspace/bitstream/10119/4464/1/73-61.pdf)
@@ -251,8 +263,8 @@ Four different EC curve parameters generation methods are implemented.
ecgen can be built using Make or CMake. ecgen uses git submodules for testing at:
- `test/lib/assert.sh` pointing at <https://github.com/J08nY/assert.sh>
- - `test/lib/JSON.sh` pointing at <https://github.com/jimklimov/JSON.sh>
- - `test/lib/criterion` pointing at <https://github.com/Snaipe/Criterion>
+ - `test/lib/JSON.sh` pointing at <https://github.com/J08nY/JSON.sh>
+ - `test/lib/criterion` pointing at <https://github.com/Snaipe/Criterion>, its build requires meson.
these need to be initialized for `make test` to work.
diff --git a/docs/readme.md b/docs/readme.md
index 2fc5335..a5a2436 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -1,4 +1,5 @@
# ecgen docs
+There is little information here. I am sorry about that :(
- [Output](output.md)
- [Points](points.md)
diff --git a/src/cm/cm.c b/src/cm/cm.c
index d49ec76..b606f83 100644
--- a/src/cm/cm.c
+++ b/src/cm/cm.c
@@ -19,22 +19,25 @@
#include "util/str.h"
static void cm_ginit(gen_f *generators, bool prime) {
+ GET(field);
+
// SEED unused.
generators[OFFSET_SEED] = &gen_skip;
// Setup stuff so it can be overridden.
- if (cfg->unique) {
+ if (GET_BOOL(unique)) {
generators[OFFSET_GENERATORS] = &gens_gen_one;
} else {
generators[OFFSET_GENERATORS] = &gens_gen_any;
}
- if (cfg->metadata) {
+ if (GET_BOOL(metadata)) {
generators[OFFSET_METADATA] = &metadata_gen;
} else {
generators[OFFSET_METADATA] = &gen_skip;
}
+ GET(points);
switch (cfg->points.type) {
case POINTS_RANDOM:
if (cfg->points.amount) {
@@ -58,6 +61,7 @@ static void cm_ginit(gen_f *generators, bool prime) {
}
// Now do the actual CM setup.
+ GET(method);
if (cfg->method == METHOD_CM) {
generators[OFFSET_FIELD] = &gen_skip;
generators[OFFSET_A] = &gen_skip;
@@ -76,6 +80,7 @@ static void cm_ginit(gen_f *generators, bool prime) {
generators[OFFSET_CURVE] = &curve_gen_any;
generators[OFFSET_ORDER] = &anomalous_gen_order;
} else if (cfg->method == METHOD_SUPERSINGULAR) {
+ GET(random);
if (cfg->random & RANDOM_FIELD) {
generators[OFFSET_FIELD] = &field_gen_random;
} else {
@@ -123,13 +128,20 @@ static void cm_ainit(arg_t **gen_argss, arg_t **check_argss,
points_arg->nargs = 1;
gen_argss[OFFSET_POINTS] = points_arg;
}
+
+ if (cfg->hex_check) {
+ arg_t *point_arg = arg_new();
+ point_arg->args = cfg->hex_check;
+ point_arg->nargs = 1;
+ check_argss[OFFSET_POINTS] = point_arg;
+ }
}
static void cm_cinit(check_t **validators) {
check_t *curve_check = check_new(curve_check_nonzero, NULL);
validators[OFFSET_CURVE] = curve_check;
- if (cfg->hex_check) {
+ if (GET_BOOL(hex_check)) {
check_t *hex_check = check_new(hex_check_param, NULL);
validators[OFFSET_POINTS] = hex_check;
}
@@ -140,6 +152,7 @@ static int cm_init(exhaustive_t *setup) {
char *order_s = NULL;
if (cfg->method == METHOD_CM) {
+ GET(cm_order);
size_t delims = str_cnt(cfg->cm_order, ',');
GEN order;
if (delims == 0) {
@@ -234,7 +247,7 @@ int cm_do() {
if (result) {
return result;
}
-
+ config_report_unused();
result = exhaustive_generate(&setup);
cm_quit(&setup);
diff --git a/src/exhaustive/exhaustive.c b/src/exhaustive/exhaustive.c
index 4eba6bd..413f93b 100644
--- a/src/exhaustive/exhaustive.c
+++ b/src/exhaustive/exhaustive.c
@@ -43,20 +43,22 @@ void exhaustive_clear(exhaustive_t *setup) {
}
static void exhaustive_ginit(gen_f *generators) {
- if (cfg->seed_algo) {
- if (cfg->prime) {
+ GET(field);
+
+ if (GET_BOOL(seed_algo)) {
+ if (GET_BOOL(prime)) {
generators[OFFSET_ORDER] = &order_gen_prime;
- } else if (cfg->cofactor) {
+ } else if (GET_BOOL(cofactor)) {
generators[OFFSET_ORDER] = &order_gen_cofactor;
- } else if (cfg->smooth) {
+ } else if (GET_BOOL(smooth)) {
generators[OFFSET_ORDER] = &order_gen_smooth;
} else {
generators[OFFSET_ORDER] = &order_gen_any;
}
- if (cfg->unique) {
+ if (GET_BOOL(unique)) {
generators[OFFSET_GENERATORS] = &gens_gen_one;
- } else if (cfg->cofactor) {
+ } else if (GET_BOOL(cofactor)) {
generators[OFFSET_GENERATORS] = &gens_gen_cofactor;
} else {
generators[OFFSET_GENERATORS] = &gens_gen_any;
@@ -65,15 +67,18 @@ static void exhaustive_ginit(gen_f *generators) {
switch (cfg->seed_algo) {
case SEED_ANSI: {
// setup ANSI X9.62 generators
+ GET(seed);
if (cfg->seed) {
generators[OFFSET_SEED] = &ansi_gen_seed_argument;
} else {
+ GET(random);
if (cfg->random & RANDOM_SEED) {
generators[OFFSET_SEED] = &ansi_gen_seed_random;
} else {
generators[OFFSET_SEED] = &ansi_gen_seed_input;
}
}
+ GET(random);
if (cfg->random & RANDOM_FIELD) {
generators[OFFSET_FIELD] = &field_gen_random;
} else {
@@ -83,9 +88,11 @@ static void exhaustive_ginit(gen_f *generators) {
generators[OFFSET_B] = &ansi_gen_equation;
} break;
case SEED_BRAINPOOL: {
+ GET(seed);
if (cfg->seed) {
generators[OFFSET_SEED] = &brainpool_gen_seed_argument;
} else {
+ GET(random);
if (cfg->random & RANDOM_SEED) {
generators[OFFSET_SEED] = &brainpool_gen_seed_random;
} else {
@@ -99,9 +106,11 @@ static void exhaustive_ginit(gen_f *generators) {
generators[OFFSET_GENERATORS] = &brainpool_gen_gens;
} break;
case SEED_BRAINPOOL_RFC: {
+ GET(seed);
if (cfg->seed) {
generators[OFFSET_SEED] = &brainpool_rfc_gen_seed_argument;
} else {
+ GET(random);
if (cfg->random & RANDOM_SEED) {
generators[OFFSET_SEED] =
&brainpool_rfc_gen_seed_random;
@@ -132,13 +141,15 @@ static void exhaustive_ginit(gen_f *generators) {
// setup normal generators
generators[OFFSET_SEED] = &gen_skip;
+ GET(random);
if (cfg->random & RANDOM_FIELD) {
generators[OFFSET_FIELD] = &field_gen_random;
} else {
generators[OFFSET_FIELD] = &field_gen_input;
}
- if (cfg->koblitz) {
+ if (GET_BOOL(koblitz)) {
+ GET(koblitz_value);
switch (cfg->koblitz_value) {
case 0:
generators[OFFSET_A] = &a_gen_zero;
@@ -151,12 +162,14 @@ static void exhaustive_ginit(gen_f *generators) {
}
generators[OFFSET_B] = &b_gen_one;
} else {
+ GET(random);
if (cfg->random & RANDOM_A) {
generators[OFFSET_A] = &a_gen_random;
} else {
generators[OFFSET_A] = &a_gen_input;
}
+ GET(random);
if (cfg->random & RANDOM_B) {
generators[OFFSET_B] = &b_gen_random;
} else {
@@ -164,21 +177,21 @@ static void exhaustive_ginit(gen_f *generators) {
}
}
- if (cfg->prime) {
+ if (GET_BOOL(prime)) {
generators[OFFSET_ORDER] = &order_gen_prime;
- } else if (cfg->cofactor) {
+ } else if (GET_BOOL(cofactor)) {
generators[OFFSET_ORDER] = &order_gen_cofactor;
- } else if (cfg->smooth) {
+ } else if (GET_BOOL(smooth)) {
generators[OFFSET_ORDER] = &order_gen_smooth;
- } else if (cfg->koblitz) {
+ } else if (GET_BOOL(koblitz)) {
generators[OFFSET_ORDER] = &order_gen_koblitz;
} else {
generators[OFFSET_ORDER] = &order_gen_any;
}
- if (cfg->unique) {
+ if (GET_BOOL(unique)) {
generators[OFFSET_GENERATORS] = &gens_gen_one;
- } else if (cfg->cofactor) {
+ } else if (GET_BOOL(cofactor)) {
generators[OFFSET_GENERATORS] = &gens_gen_cofactor;
} else {
generators[OFFSET_GENERATORS] = &gens_gen_any;
@@ -186,18 +199,21 @@ static void exhaustive_ginit(gen_f *generators) {
}
// setup common generators
+ GET(method);
if (cfg->method == METHOD_TWIST) {
generators[OFFSET_CURVE] = &curve_gen_any_twist;
} else {
generators[OFFSET_CURVE] = &curve_gen_any;
}
+ GET(metadata);
if (cfg->metadata) {
generators[OFFSET_METADATA] = &metadata_gen;
} else {
generators[OFFSET_METADATA] = &gen_skip;
}
+ GET(points);
switch (cfg->points.type) {
case POINTS_RANDOM:
if (cfg->points.amount) {
@@ -225,12 +241,14 @@ static void exhaustive_cinit(check_t **validators) {
check_t *curve_check = check_new(curve_check_nonzero, NULL);
validators[OFFSET_CURVE] = curve_check;
- if (cfg->hex_check) {
+ if (GET_BOOL(hex_check)) {
check_t *hex_check = check_new(hex_check_param, NULL);
validators[OFFSET_POINTS] = hex_check;
}
+ GET(method);
if (cfg->method == METHOD_SEED) {
+ GET(seed_algo);
switch (cfg->seed_algo) {
case SEED_ANSI:
break;
@@ -466,6 +484,7 @@ int exhaustive_do() {
.check_argss = check_argss,
.unrolls = unrolls};
exhaustive_init(&setup);
+ config_report_unused();
int result = exhaustive_generate(&setup);
exhaustive_quit(&setup);
debug_log_end("Finished Exhaustive method");
diff --git a/src/invalid/invalid.c b/src/invalid/invalid.c
index da2a0b3..d7433fc 100644
--- a/src/invalid/invalid.c
+++ b/src/invalid/invalid.c
@@ -17,7 +17,10 @@
#include "util/memory.h"
static void invalid_original_ginit(gen_f *generators) {
+ GET(field);
+
generators[OFFSET_SEED] = &gen_skip;
+ GET(random);
if (cfg->random & RANDOM_FIELD) {
generators[OFFSET_FIELD] = &field_gen_random;
} else {
@@ -46,7 +49,7 @@ static void invalid_invalid_ginit(gen_f *generators) {
generators[OFFSET_B] = &b_gen_random;
generators[OFFSET_CURVE] = &curve_gen_any;
generators[OFFSET_ORDER] = &order_gen_any;
- if (cfg->unique) {
+ if (GET_BOOL(unique)) {
generators[OFFSET_GENERATORS] = &gens_gen_one;
} else {
generators[OFFSET_GENERATORS] = &gens_gen_any;
@@ -74,6 +77,7 @@ static size_t invalid_primes(GEN order, pari_ulong **primes) {
pari_ulong upper = 0;
size_t nprimes = 0;
+ GET(invalid_primes);
if (cfg->invalid_primes) {
char *end = NULL;
last = (pari_ulong)strtol(cfg->invalid_primes, &end, 10) - 1;
@@ -349,6 +353,7 @@ int invalid_do() {
.check_argss = common_check_argss,
.unrolls = common_unrolls};
invalid_invalid_ginit(invalid_gens);
+ config_report_unused();
debug_log_start("Starting to create curve to invalidate");
curve_t *curve = invalid_original_curve(&original_setup);
diff --git a/src/io/cli.c b/src/io/cli.c
index d6bb9e0..5307d70 100644
--- a/src/io/cli.c
+++ b/src/io/cli.c
@@ -226,41 +226,51 @@ error_t cli_parse(int key, char *arg, struct argp_state *state) {
/* Field options */
case OPT_FP:
cfg->field |= FIELD_PRIME;
+ SET(field);
break;
case OPT_F2M:
cfg->field |= FIELD_BINARY;
+ SET(field);
break;
/* Generation method */
case OPT_INVALID:
cfg->method |= METHOD_INVALID;
+ SET(method);
if (arg) {
size_t span = strspn(arg, "0123456789-");
if (span != strlen(arg)) {
argp_failure(state, 1, 0, "Invalid range %s", arg);
}
cfg->invalid_primes = arg;
+ SET(invalid_primes);
}
break;
case OPT_ORDER:
cfg->method |= METHOD_CM;
+ SET(method);
if (arg) {
int error = regexec(&re_cm_order, arg, 0, NULL, 0);
if (error != 0) {
argp_failure(state, 1, 0, "Invalid order %s", arg);
}
cfg->cm_order = arg;
+ SET(cm_order);
}
break;
case OPT_ANOMALOUS:
cfg->method |= METHOD_ANOMALOUS;
+ SET(method);
break;
case OPT_SUPERSINGULAR:
cfg->method |= METHOD_SUPERSINGULAR;
+ SET(method);
break;
case OPT_ANSI:
cfg->method |= METHOD_SEED;
+ SET(method);
cfg->seed_algo = SEED_ANSI;
+ SET(seed_algo);
if (arg) {
if (!ansi_seed_valid(arg)) {
argp_failure(
@@ -268,11 +278,14 @@ error_t cli_parse(int key, char *arg, struct argp_state *state) {
"SEED must be at least 160 bits (40 characters).");
}
cfg->seed = arg;
+ SET(seed);
}
break;
case OPT_BRAINPOOL:
cfg->method |= METHOD_SEED;
+ SET(method);
cfg->seed_algo = SEED_BRAINPOOL;
+ SET(seed_algo);
if (arg) {
if (!brainpool_seed_valid(arg)) {
argp_failure(
@@ -280,15 +293,20 @@ error_t cli_parse(int key, char *arg, struct argp_state *state) {
"SEED must be exactly 160 bits (40 hex characters).");
}
cfg->seed = arg;
+ SET(seed);
}
break;
case OPT_NUMS:
cfg->method |= METHOD_SEED;
+ SET(method);
cfg->seed_algo = SEED_NUMS;
+ SET(seed_algo);
break;
case OPT_BRAINPOOL_RFC:
cfg->method |= METHOD_SEED;
+ SET(method);
cfg->seed_algo = SEED_BRAINPOOL_RFC;
+ SET(seed_algo);
if (arg) {
if (!brainpool_seed_valid(arg)) {
argp_failure(
@@ -296,15 +314,18 @@ error_t cli_parse(int key, char *arg, struct argp_state *state) {
"SEED must be exactly 160 bits (40 hex characters).");
}
cfg->seed = arg;
+ SET(seed);
}
break;
case OPT_TWIST:
cfg->method |= METHOD_TWIST;
+ SET(method);
break;
/* Generation options */
case OPT_COUNT:
cfg->count = strtoul(arg, NULL, 10);
+ SET(count);
break;
case OPT_RANDOM:
if (arg) {
@@ -329,22 +350,28 @@ error_t cli_parse(int key, char *arg, struct argp_state *state) {
} else {
cfg->random = RANDOM_ALL;
}
+ SET(random);
break;
case OPT_PRIME:
cfg->prime = true;
+ SET(prime);
break;
case OPT_SMOOTH:
cfg->smooth = true;
+ SET(smooth);
cfg->smooth_value = strtol(arg, NULL, 10);
break;
case OPT_COFACTOR:
cfg->cofactor = true;
+ SET(cofactor);
cfg->cofactor_value = strtol(arg, NULL, 10);
break;
case OPT_KOBLITZ:
cfg->koblitz = true;
+ SET(koblitz);
if (arg) {
cfg->koblitz_value = strtol(arg, NULL, 10);
+ SET(koblitz_value);
if (cfg->koblitz_value != 0 && cfg->koblitz_value != 1) {
argp_failure(state, 1, 0, "Wrong value for a = %li",
cfg->koblitz_value);
@@ -353,6 +380,7 @@ error_t cli_parse(int key, char *arg, struct argp_state *state) {
break;
case OPT_UNIQUE:
cfg->unique = true;
+ SET(unique);
break;
case OPT_HEXCHECK: {
char *str_start = arg;
@@ -371,10 +399,12 @@ error_t cli_parse(int key, char *arg, struct argp_state *state) {
}
}
cfg->hex_check = str_start;
+ SET(hex_check);
break;
}
case OPT_METADATA:
cfg->metadata = true;
+ SET(metadata);
break;
case OPT_POINTS: {
char *num_end;
@@ -393,6 +423,7 @@ error_t cli_parse(int key, char *arg, struct argp_state *state) {
} else {
argp_failure(state, 1, 0, "Unknown point type. %s", num_end);
}
+ SET(points);
break;
}
/* IO options */
diff --git a/src/misc/config.c b/src/misc/config.c
index 78b44ca..8beeae0 100644
--- a/src/misc/config.c
+++ b/src/misc/config.c
@@ -3,6 +3,95 @@
* Copyright (C) 2017-2018 J08nY
*/
#include "config.h"
+#include <stdio.h>
config_t cfg_s;
-config_t *cfg = &cfg_s; \ No newline at end of file
+config_t *cfg = &cfg_s;
+
+config_names_t cfg_used_s = {0};
+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() {
+ if (cfg_set->field && !cfg_used->field) {
+ fprintf(
+ stderr,
+ "Warning: Ignored command-line argument \"field\" (--fp/--f2m).\n");
+ }
+ if (cfg_set->method && !cfg_used->method) {
+ fprintf(stderr, "Warning: Ignored command-line argument method.\n");
+ }
+ if (cfg_set->count && !cfg_used->count) {
+ fprintf(stderr,
+ "Warning: Ignored command-line argument count (-c/--count).\n");
+ }
+ if (cfg_set->random && !cfg_used->random) {
+ fprintf(
+ stderr,
+ "Warning: Ignored command-line argument random (-r/--random).\n");
+ }
+ if (cfg_set->prime && !cfg_used->prime) {
+ fprintf(stderr,
+ "Warning: Ignored command-line argument prime (-p/--prime).\n");
+ }
+ if (cfg_set->cm_order && !cfg_used->cm_order) {
+ fprintf(
+ stderr,
+ "Warning: Ignored command-line argument cm_order (-n/--order).\n");
+ }
+ if (cfg_set->koblitz && !cfg_used->koblitz) {
+ fprintf(
+ stderr,
+ "Warning: Ignored command-line argument koblitz (-K/--koblitz).\n");
+ }
+ if (cfg_set->koblitz_value && !cfg_used->koblitz_value) {
+ fprintf(stderr,
+ "Warning: Ignored command-line argument koblitz_value "
+ "(-K/--koblitz).\n");
+ }
+ if (cfg_set->smooth && !cfg_used->smooth) {
+ fprintf(
+ stderr,
+ "Warning: Ignored command-line argument smooth (-B/--smooth).\n");
+ }
+ if (cfg_set->cofactor && !cfg_used->cofactor) {
+ fprintf(stderr,
+ "Warning: Ignored command-line argument cofactor "
+ "(-k/--cofactor).\n");
+ }
+ if (cfg_set->invalid_primes && !cfg_used->invalid_primes) {
+ fprintf(stderr,
+ "Warning: Ignored command-line argument invalid_primes "
+ "(-i/--invalid).\n");
+ }
+ if (cfg_set->seed_algo && !cfg_used->seed_algo) {
+ fprintf(
+ stderr,
+ "Warning: Ignored command-line argument seed_algo (-s/--ansi).\n");
+ }
+ if (cfg_set->seed && !cfg_used->seed) {
+ fprintf(stderr,
+ "Warning: Ignored command-line argument seed (-s/--ansi).\n");
+ }
+ if (cfg_set->unique && !cfg_used->unique) {
+ fprintf(
+ stderr,
+ "Warning: Ignored command-line argument unique (-u/--unique).\n");
+ }
+ if (cfg_set->hex_check && !cfg_used->hex_check) {
+ fprintf(stderr,
+ "Warning: Ignored command-line argument hex_check "
+ "(--hex-check).\n");
+ }
+ if (cfg_set->points && !cfg_used->points) {
+ fprintf(stderr,
+ "Warning: Ignored command-line argument points (--points).\n");
+ }
+ if (cfg_set->metadata && !cfg_used->metadata) {
+ fprintf(
+ stderr,
+ "Warning: Ignored command-line argument metadata (--metadata).\n");
+ }
+} \ No newline at end of file
diff --git a/src/misc/config.h b/src/misc/config.h
index dcdca58..0c0a5ca 100644
--- a/src/misc/config.h
+++ b/src/misc/config.h
@@ -142,4 +142,36 @@ typedef struct {
extern config_t cfg_s;
extern config_t *cfg;
+typedef struct {
+ bool field;
+ bool method;
+ bool count;
+ bool random;
+ bool prime;
+ bool cm_order;
+ bool koblitz;
+ bool koblitz_value;
+ bool smooth;
+ bool cofactor;
+ bool invalid_primes;
+ bool seed_algo;
+ bool seed;
+ bool unique;
+ bool hex_check;
+ bool points;
+ bool metadata;
+} config_names_t;
+
+extern config_names_t cfg_used_s;
+extern config_names_t *cfg_used;
+
+extern config_names_t cfg_set_s;
+extern config_names_t *cfg_set;
+
+#define GET(x) cfg_used->x = true
+#define GET_BOOL(x) ((cfg_used->x = true) && cfg->x)
+#define SET(x) cfg_set->x = true
+
+void config_report_unused();
+
#endif // ECGEN_MISC_CONFIG_H