diff options
| -rw-r--r-- | README.md | 7 | ||||
| -rw-r--r-- | src/exhaustive/exhaustive.c | 14 | ||||
| -rw-r--r-- | src/invalid/invalid.c | 4 | ||||
| -rw-r--r-- | src/io/cli.c | 65 | ||||
| -rw-r--r-- | src/io/cli.h | 2 | ||||
| -rw-r--r-- | src/io/output.c | 135 | ||||
| -rw-r--r-- | src/io/output.h | 75 |
7 files changed, 241 insertions, 61 deletions
@@ -15,8 +15,10 @@ Tool for generating Elliptic curve domain parameters. - `-n/--order=ORDER` requests the curve to have a (prime) order `ORDER`. - `-i/--invalid` requests that invalid curves of small prime orders be generated. <br/><br/> - - `-o/--output=FILE` writes output to `FILE`. + - `-v/--verbose=[FILE]` turns on verbose output (to file). + - `-t/--format=[FORMAT]` sets format to output in. One of \[csv,json\], default is json. - `-f/--input=FILE` reads input from `FILE`. + - `-o/--output=FILE` writes output to `FILE`. - `-a/--append` appends to output file (doesn't overwrite it). <br/><br/> - `-d/--datadir=DIR` specifies the PARI/GP datadir containing the `seadata` package. @@ -29,6 +31,9 @@ Three different EC curve parameters generation methods are implemented. - randomly - using ANSI X9.62 verifiably random method(from seed), until a curve with requested properties appears. - given input + - Can generate curves repeatedly until one satisfies requested properties: + - `-p/--prime` generates curves until a prime order curve is found. + - `-k/--koblitz` generates a curve with fixed *A = 0* parameter. ##### Invalid curve generation - Generates *invalid* curves for a given curve. diff --git a/src/exhaustive/exhaustive.c b/src/exhaustive/exhaustive.c index 00905c5..4d6e7a9 100644 --- a/src/exhaustive/exhaustive.c +++ b/src/exhaustive/exhaustive.c @@ -69,18 +69,18 @@ int exhaustive_gen(curve_t *curve, config_t *config, gen_t generators[], } if (config->verbose) { if (diff > 0) { - fprintf(out, "+"); + fprintf(debug, "+"); } else if (diff < 0) { - fprintf(out, "-"); + fprintf(debug, "-"); } else { - fprintf(out, "."); + fprintf(debug, "."); } - fflush(out); + fflush(debug); } state += diff; } - if (config->verbose) fprintf(out, "\n"); + if (config->verbose) fprintf(debug, "\n"); return 1; } @@ -90,11 +90,11 @@ int exhaustive_do(config_t *cfg) { exhaustive_init(generators, cfg); curve_t *curve = curve_new(); - if (!exhaustive_gen(curve, cfg, generators, OFFSET_FIELD, OFFSET_END)) { + if (!exhaustive_gen(curve, cfg, generators, OFFSET_SEED, OFFSET_END)) { curve_free(&curve); return 1; } - output_csv(out, "%P#x", ',', curve_params(curve)); + output_o(curve, cfg); curve_free(&curve); return 0; }
\ No newline at end of file diff --git a/src/invalid/invalid.c b/src/invalid/invalid.c index 1c21f89..72a9877 100644 --- a/src/invalid/invalid.c +++ b/src/invalid/invalid.c @@ -108,7 +108,7 @@ size_t invalid_curves(curve_t *curve, config_t *cfg, pari_ulong *primes, (*curves)[i] = curve_new(); (*curves)[i] = curve_copy(invalid, (*curves)[i]); } - output_csv(out, "%P#x", ',', curve_params((*curves)[i])); + output_o((*curves)[i], cfg); ncurves++; count++; } @@ -136,7 +136,7 @@ int invalid_do(config_t *cfg) { curve_free(&curve); return 1; } - output_csv(out, "%P#x", ',', curve_params(curve)); + output_o(curve, cfg); // now, generate primes upto order^2 pari_ulong *primes; diff --git a/src/io/cli.c b/src/io/cli.c index 6aaadc8..f9097d9 100644 --- a/src/io/cli.c +++ b/src/io/cli.c @@ -6,8 +6,8 @@ #include <string.h> char doc[] = - "ecgen, tool for generating Elliptic curve domain parameters.\v(C) 2017 " - "Eastern Seaboard Phishing Authority"; + "ecgen, tool for generating Elliptic curve domain parameters.\v(C) 2017 " + "Eastern Seaboard Phishing Authority"; char args_doc[] = "bits"; enum opt_keys { @@ -18,6 +18,7 @@ enum opt_keys { OPT_INVALID = 'i', OPT_ORDER = 'n', OPT_KOBLITZ = 'k', + OPT_FORMAT = 't', OPT_OUTPUT = 'o', OPT_INPUT = 'f', OPT_APPEND = 'a', @@ -29,21 +30,22 @@ enum opt_keys { // clang-format off struct argp_option options[] = { // Field specification - {"fp", OPT_FP, 0, 0, "Prime field."}, - {"f2m", OPT_F2M, 0, 0, "Binary field."}, + {"fp", OPT_FP, 0, 0, "Prime field."}, + {"f2m", OPT_F2M, 0, 0, "Binary field."}, // Curve specification - {"random", OPT_RANDOM, 0, 0, "Generate a random curve."}, - {"prime", OPT_PRIME, 0, 0, "Generate a curve with prime order."}, + {"random", OPT_RANDOM, 0, 0, "Generate a random curve."}, + {"prime", OPT_PRIME, 0, 0, "Generate a curve with prime order."}, {"seed", OPT_SEED, "SEED", OPTION_ARG_OPTIONAL, "Generate a curve from SEED (ANSI X9.62 verifiable procedure)."}, - {"invalid", OPT_INVALID, 0, 0, "Generate a set of invalid curves (for a given curve)."}, - {"order", OPT_ORDER, "ORDER", 0, "Generate a curve with given order (using Complex Multiplication)."}, - {"koblitz", OPT_KOBLITZ, 0, 0, "Generate a Koblitz curve."}, + {"invalid", OPT_INVALID, 0, 0, "Generate a set of invalid curves (for a given curve)."}, + {"order", OPT_ORDER, "ORDER", 0, "Generate a curve with given order (using Complex Multiplication)."}, + {"koblitz", OPT_KOBLITZ, 0, 0, "Generate a Koblitz curve."}, // Other - {"data-dir", OPT_DATADIR, "DIR", 0, "PARI/GP data directory (containing seadata package)."}, - {"input", OPT_INPUT, "FILE", 0, "Input from file."}, - {"output", OPT_OUTPUT, "FILE", 0, "Output into file. Overwrites any existing file!"}, - {"append", OPT_APPEND, 0, 0, "Append to output file (don't overwrite)."}, - {"verbose", OPT_VERBOSE, "FILE", OPTION_ARG_OPTIONAL, "Verbose logging to stdout"}, + {"data-dir", OPT_DATADIR, "DIR", 0, "PARI/GP data directory (containing seadata package)."}, + {"format", OPT_FORMAT, "FORMAT", 0, "Format to output in. One of [csv,json], default is json."}, + {"input", OPT_INPUT, "FILE", 0, "Input from file."}, + {"output", OPT_OUTPUT, "FILE", 0, "Output into file. Overwrites any existing file!"}, + {"append", OPT_APPEND, 0, 0, "Append to output file (don't overwrite)."}, + {"verbose", OPT_VERBOSE, "FILE", OPTION_ARG_OPTIONAL, "Verbose logging (to stdout or file)."}, {0}}; // clang-format on @@ -54,6 +56,21 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) { case OPT_DATADIR: cfg->datadir = arg; break; + case OPT_FORMAT: + if (arg) { + if (!strcmp(arg, "csv")) { + cfg->format = FORMAT_CSV; + } else if (!strcmp(arg, "json")) { + cfg->format = FORMAT_JSON; + } else { + argp_failure(state, 1, 0, + "Invalid format specified. One of [csv, json] is valid."); + } + } else { + argp_failure(state, 1, 0, + "You have to specify a format with the format option."); + } + break; case OPT_INPUT: cfg->input = arg; break; @@ -93,8 +110,8 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) { // ANSI X9.62 specifies seed as at least 160 bits in length. if (strlen(arg) < 20) { argp_failure( - state, 1, 0, - "SEED must be at least 160 bits (20 characters)."); + state, 1, 0, + "SEED must be at least 160 bits (20 characters)."); } cfg->seed = arg; } @@ -119,22 +136,22 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) { // Only one field if (!cfg->prime_field && !cfg->binary_field) { argp_failure(state, 1, 0, - "Specify field type, prime or binary, with --fp / " - "--f2m (but not both)."); + "Specify field type, prime or binary, with --fp / " + "--f2m (but not both)."); } // Invalid is not prime or seed by definition. if (cfg->invalid && (cfg->prime || cfg->from_seed)) { // not seed, not prime argp_failure(state, 1, 0, - "Invalid curve generation can not generate curves " - "from seed, exhaustive or prime order."); + "Invalid curve generation can not generate curves " + "from seed, exhaustive or prime order."); } if (cfg->cm && (cfg->prime || cfg->from_seed || cfg->invalid)) { argp_failure(state, 1, 0, - "Fixed order curve generation can not generate " - "curves from seed, or invalid curves. Prime order " - "also doesn't make sense if the given one isn't " - "prime."); + "Fixed order curve generation can not generate " + "curves from seed, or invalid curves. Prime order " + "also doesn't make sense if the given one isn't " + "prime."); } break; case ARGP_KEY_NO_ARGS: diff --git a/src/io/cli.h b/src/io/cli.h index 52b39ec..152a129 100644 --- a/src/io/cli.h +++ b/src/io/cli.h @@ -14,6 +14,7 @@ extern char args_doc[]; extern struct argp_option options[]; enum field_e { FIELD_PRIME, FIELD_BINARY }; +enum format_e { FORMAT_JSON, FORMAT_CSV }; typedef struct config_t { enum field_e field; @@ -28,6 +29,7 @@ typedef struct config_t { bool from_seed; char *seed; char *datadir; + enum format_e format; char *output; char *input; bool append; diff --git a/src/io/output.c b/src/io/output.c index 1b4b16b..7b3e8a1 100644 --- a/src/io/output.c +++ b/src/io/output.c @@ -5,17 +5,23 @@ #include "output.h" #include <parson/parson.h> +#include "math/field.h" +#include "math/curve.h" + FILE *out; FILE *debug; -char *output_scsv(const char *format, char delim, GEN vector) { - long len = lg(vector) - 1; +char *output_scsv(curve_t *curve, config_t *config) { + pari_sp ltop = avma; + GEN vector = curve_params(curve); + + long len = glength(vector); char *params[len]; size_t lengths[len]; size_t total = 0; for (long i = 0; i < len; ++i) { - params[i] = pari_sprintf(format, gel(vector, i + 1)); + params[i] = pari_sprintf("%P#x", gel(vector, i + 1)); lengths[i] = strlen(params[i]); total += lengths[i]; } @@ -33,34 +39,111 @@ char *output_scsv(const char *format, char delim, GEN vector) { offset += lengths[i]; if (i != len - 1) { - result[offset] = delim; + result[offset] = ','; offset++; } } memset(result + offset, 0, 1); + avma = ltop; return result; } -void output_csv(FILE *out, const char *format, char delim, GEN vector) { - char *string = output_scsv(format, delim, vector); +void output_fcsv(FILE *out, curve_t *curve, config_t *config) { + char *string = output_scsv(curve, config); fprintf(out, "%s\n", string); free(string); } +void output_csv(curve_t *curve, config_t *config) { + output_fcsv(out, curve, config); +} -char *output_sjson(curve_t *curve) { - /* +JSON_Value *output_jjson(curve_t *curve, config_t *config) { + pari_sp ltop = avma; + // root object/value is curve JSON_Value *root_value = json_value_init_object(); JSON_Object *root_object = json_value_get_object(root_value); - char *result = NULL; - */ - //TODO implement - return NULL; + + switch (config->field) { + case FIELD_PRIME: { + char *prime = pari_sprintf("%P#x", curve->field); + json_object_dotset_string(root_object, "field.p", prime); + pari_free(prime); + break; + } + case FIELD_BINARY: { + GEN field = field_params(curve->field); + char *e1 = pari_sprintf("%P#x", gel(field, 1)); + char *e2 = pari_sprintf("%P#x", gel(field, 2)); + char *e3 = pari_sprintf("%P#x", gel(field, 3)); + char *m = pari_sprintf("%#lx", config->bits); // maybe not? + json_object_dotset_string(root_object, "field.m", m); + json_object_dotset_string(root_object, "field.e1", e1); + json_object_dotset_string(root_object, "field.e2", e2); + json_object_dotset_string(root_object, "field.e3", e3); + pari_free(m); + pari_free(e1); + pari_free(e2); + pari_free(e3); + break; + } + default: + fprintf(stderr, "Error, field has unknown amount of elements.\n"); + exit(1); + } + + char *a = pari_sprintf("%P#x", field_elementi(curve->a)); + json_object_set_string(root_object, "a", a); + pari_free(a); + char *b = pari_sprintf("%P#x", field_elementi(curve->b)); + json_object_set_string(root_object, "b", b); + pari_free(b); + char *order = pari_sprintf("%P#x", curve->order); + json_object_set_string(root_object, "order", order); + pari_free(order); + if (curve->npoints) { + JSON_Value *points_value = json_value_init_array(); + JSON_Array *points_array = json_value_get_array(points_value); + + for (size_t i = 0; i < curve->npoints; ++i) { + JSON_Value *point_value = json_value_init_object(); + JSON_Object *point_object = json_value_get_object(point_value); + + char *x = pari_sprintf("%P#x", field_elementi(gel(curve->points[i]->point, 1))); + json_object_set_string(point_object, "x", x); + pari_free(x); + char *y = pari_sprintf("%P#x", field_elementi(gel(curve->points[i]->point, 2))); + json_object_set_string(point_object, "y", y); + pari_free(y); + char *p_order = pari_sprintf("%P#x", curve->points[i]->order); + json_object_set_string(point_object, "order", p_order); + pari_free(p_order); + json_array_append_value(points_array, point_value); + } + + json_object_set_value(root_object, "points", points_value); + } + avma = ltop; + return root_value; } -void output_json(FILE *out, GEN vector) { - //TODO implement +char *output_sjson(curve_t *curve, config_t *config) { + JSON_Value *root_value = output_jjson(curve, config); + char *result = json_serialize_to_string_pretty(root_value); + json_value_free(root_value); + + return result; +} + +void output_fjson(FILE *out, curve_t *curve, config_t *config) { + char *s = output_sjson(curve, config); + fprintf(out, "%s", s); + json_free_serialized_string(s); +} + +void output_json(curve_t *curve, config_t *config) { + output_fjson(out, curve, config); } void output_init(config_t *cfg) { @@ -76,10 +159,32 @@ void output_init(config_t *cfg) { } else { out = stdout; } + if (cfg->debug) { + debug = fopen(cfg->debug, "w"); + if (!debug) { + debug = stdout; + perror("Failed to open verbose output file."); + } + } else { + debug = stdout; + } + + switch (cfg->format) { + case FORMAT_JSON: + output_s = &output_sjson; + output_f = &output_fjson; + output_o = &output_json; + break; + case FORMAT_CSV: + output_s = &output_scsv; + output_f = &output_fcsv; + output_o = &output_csv; + break; + } } void output_quit(void) { if (out != NULL && out != stdout) { fclose(out); } -}
\ No newline at end of file +} diff --git a/src/io/output.h b/src/io/output.h index b2b32ac..5aca4bd 100644 --- a/src/io/output.h +++ b/src/io/output.h @@ -11,41 +11,92 @@ /** * - * @param delim - * @param format - * @param vector + * @param curve + * @param config * @return */ -char *output_scsv(const char *format, char delim, GEN vector); +char *output_scsv(curve_t *curve, config_t *config); /** * * @param out - * @param delim - * @param format - * @param vector + * @param curve + * @param config */ -void output_csv(FILE *out, const char *format, char delim, GEN vector); +void output_fcsv(FILE *out, curve_t *curve, config_t *config); /** * - * @param vector + * @param curve + * @param config + */ +void output_csv(curve_t *curve, config_t *config); + +/** + * + * @param curve + * @param config + * @return + */ +char *output_sjson(curve_t *curve, config_t *config); + +/** + * + * @param out + * @param curve + * @param config + */ +void output_fjson(FILE *out, curve_t *curve, config_t *config); + +/** + * + * @param curve + * @param config + */ +void output_json(curve_t *curve, config_t *config); + +/** + * + * @param curve + * @param config * @return */ -char *output_sjson(curve_t *curve); +char *(*output_s)(curve_t *curve, config_t *config); /** * * @param out - * @param vector + * @param curve + * @param config */ -void output_json(FILE *out, GEN vector); +void (*output_f)(FILE *out, curve_t *curve, config_t *config); +/** + * + * @param curve + * @param config + */ +void (*output_o)(curve_t *curve, config_t *config); + +/** + * + */ extern FILE *out; + +/** + * + */ extern FILE *debug; +/** + * + * @param cfg + */ void output_init(config_t *cfg); +/** + * + */ void output_quit(void); #endif // ECGEN_OUTPUT_H |
