diff --git a/README.md b/README.md index 6b2b48c..d8d13ac 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Tool for generating Elliptic curve domain parameters. - `-s / --ansi[=SEED]` Generate a curve from `SEED` (ANSI X9.62 verifiable procedure). - `-b / --brainpool[=SEED]`Generate a curve using the Brainpool verifiably pseudorandom algorithm from the original paper. - `--brainpool-rfc[=SEED]` Generate a curve using the Brainpool verifiably pseudorandom algorithm as per RFC 5639. + - `--nums` Generate a curve using the NUMS procedure (as per draft-black-numscurves-02). - `--twist` Generate a twist of a given curve. #### Generation options @@ -34,6 +35,7 @@ Tool for generating Elliptic curve domain parameters. - `--points=TYPE` Generate points of given `TYPE` (random/prime/all/nonprime/none). - `-r / --random` Generate a random curve (using Random approach). - `-u / --unique` Generate a curve with only one generator. + - `--hex-check=HEX` Generate a curve with `HEX` string in the hex expansion of its parameters. - `--metadata` Compute the curve metadata (j-invariant, discriminant, trace of Frobenius, CM discriminant, embedding degree) #### IO options diff --git a/src/exhaustive/exhaustive.c b/src/exhaustive/exhaustive.c index a8d0f22..4eba6bd 100644 --- a/src/exhaustive/exhaustive.c +++ b/src/exhaustive/exhaustive.c @@ -7,6 +7,7 @@ #include "arg.h" #include "brainpool.h" #include "brainpool_rfc.h" +#include "nums.h" #include "check.h" #include "gen/curve.h" #include "gen/equation.h" @@ -114,6 +115,14 @@ static void exhaustive_ginit(gen_f *generators) { generators[OFFSET_ORDER] = &order_gen_prime; generators[OFFSET_GENERATORS] = &brainpool_gen_gens; } break; + case SEED_NUMS: { + 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_ORDER] = &nums_gen_order; + generators[OFFSET_GENERATORS] = &nums_gen_gens; + } break; case SEED_FIPS: break; default: @@ -227,12 +236,19 @@ static void exhaustive_cinit(check_t **validators) { break; case SEED_BRAINPOOL: case SEED_BRAINPOOL_RFC: { + // TODO: Missing Brainpool CM disc check. check_t *order_check = check_new(brainpool_check_order, NULL); validators[OFFSET_ORDER] = order_check; check_t *gens_check = check_new(gens_check_anomalous, brainpool_check_gens, NULL); validators[OFFSET_GENERATORS] = gens_check; } break; + case SEED_NUMS: { + // TODO: Missing CM disc check. + check_t *gens_check = + check_new(gens_check_anomalous, brainpool_check_gens, NULL); + validators[OFFSET_GENERATORS] = gens_check; + } break; case SEED_FIPS: break; default: @@ -407,6 +423,7 @@ static void exhaustive_init(exhaustive_t *setup) { static void exhaustive_quit(exhaustive_t *setup) { field_quit(); equation_quit(); + nums_quit(); exhaustive_clear(setup); } diff --git a/src/exhaustive/nums.c b/src/exhaustive/nums.c new file mode 100644 index 0000000..7e41938 --- /dev/null +++ b/src/exhaustive/nums.c @@ -0,0 +1,111 @@ +/* + * ecgen, tool for generating Elliptic curve domain parameters + * Copyright (C) 2023 J08nY + */ + +#include "nums.h" +#include "math/subgroup.h" +#include "obj/point.h" +#include "obj/subgroup.h" + +GENERATOR(nums_gen_field) { + pari_sp ltop = avma; + GEN base = int2u(cfg->bits); + GEN c = stoi(1); + GEN p = subii(base, c); + while (!isprime(p)) { + c = addiu(c, 4); + p = subii(base, c); + } + curve->field = gerepilecopy(ltop, p); + return 1; +} + +GENERATOR(nums_gen_a) { + curve-> a = gmodulo(stoi(-3), curve->field); + return 1; +} + +static GEN b = NULL; +static curve_t *curve_b = NULL; + +GENERATOR(nums_gen_b) { + pari_sp ltop = avma; + if (!b) { + b = gclone(gen_1); + curve->b = gmodulo(gen_1, curve->field); + curve_b = curve; + return 1; + } else { + if (curve_b == curve) { + // use b, add 1 to it, store it back modified, + GEN bn; + if (equaliu(b, 1)) { + bn = addiu(b, 2); + } else { + bn = addiu(b, 1); + } + gunclone(b); + b = gclone(bn); + curve->b = gerepilecopy(ltop, gmodulo(bn, curve->field)); + return 1; + } else { + // dont use b, regenerate it, + gunclone(b); + b = gclone(gen_1); + curve->b = gerepilecopy(ltop, gmodulo(gen_1, curve->field)); + curve_b = curve; + return 1; + } + } +} + +GENERATOR(nums_gen_order) { + pari_sp ltop = avma; + GEN order = ellsea(curve->curve, 1); + GEN frobenius = subii(addis(curve->field, 1), order); + GEN twist_order = addii(order, muliu(frobenius, 2)); + if (gequal0(order) || !(isprime(order)) || !(isprime(twist_order))) { + avma = ltop; + return -2; // Just go one step back and regenerate the b. + } else { + curve->order = gerepilecopy(ltop, order); + obj_insert_shallow(curve->curve, 1, curve->order); + return 1; + } +} + +GENERATOR(nums_gen_gens) { + pari_sp ltop = avma; + GEN x = stoi(1); + GEN Qy = ellordinate(curve->curve, x, 0); + while (glength(Qy) == 0) { + x = addiu(x, 1); + Qy = ellordinate(curve->curve, x, 0); + } + GEN P = NULL; + if (cmpii(lift(gel(Qy, 1)), lift(gel(Qy, 2))) < 0) { + P = mkvec2(gmodulo(x, curve->field), gel(Qy, 1)); + } else { + P = mkvec2(gmodulo(x, curve->field), gel(Qy, 2)); + } + + curve->generators = subgroups_new(1); + curve->ngens = 1; + subgroup_t *sub = subgroup_new(); + curve->generators[0] = sub; + point_t *G = point_new(); + sub->generator = G; + G->point = P; + G->order = ellorder(curve->curve, G->point, NULL); + G->cofactor = divii(curve->order, G->order); + gerepileall(ltop, 3, &G->point, &G->order, &G->cofactor); + 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 new file mode 100644 index 0000000..40cb1b4 --- /dev/null +++ b/src/exhaustive/nums.h @@ -0,0 +1,60 @@ +/* + * ecgen, tool for generating Elliptic curve domain parameters + * Copyright (C) 2023 J08nY + */ +/* + * @file nums.h + */ +#ifndef ECGEN_EXHAUSTIVE_NUMS_H +#define ECGEN_EXHAUSTIVE_NUMS_H + +#include "misc/types.h" + +/** + * @brief + * @param curve + * @param args + * @param state + * @return + */ +GENERATOR(nums_gen_field); + +/** + * @brief + * @param curve + * @param args + * @param state + * @return + */ +GENERATOR(nums_gen_a); + +/** + * @brief + * @param curve + * @param args + * @param state + * @return + */ +GENERATOR(nums_gen_b); + +/** + * @brief + * @param curve + * @param args + * @param state + * @return + */ +GENERATOR(nums_gen_order); + +/** + * @brief + * @param curve + * @param args + * @param state + * @return + */ +GENERATOR(nums_gen_gens); + +void nums_quit(); + +#endif // ECGEN_EXHAUSTIVE_NUMS_H diff --git a/src/gen/seed.c b/src/gen/seed.c index 3b10d26..5dca17a 100644 --- a/src/gen/seed.c +++ b/src/gen/seed.c @@ -49,6 +49,8 @@ void seed_free(seed_t **seed) { break; case SEED_FIPS: break; + case SEED_NUMS: + break; case SEED_NONE: break; } diff --git a/src/io/cli.c b/src/io/cli.c index ad3df9b..fec3283 100644 --- a/src/io/cli.c +++ b/src/io/cli.c @@ -41,6 +41,7 @@ enum opt_keys { OPT_HEXCHECK, OPT_METADATA, OPT_SUPERSINGULAR, + OPT_NUMS, OPT_BRAINPOOL_RFC, OPT_TWIST, }; @@ -58,6 +59,7 @@ struct argp_option cli_options[] = { {"ansi", OPT_ANSI, "SEED", OPTION_ARG_OPTIONAL, "Generate a curve from SEED (ANSI X9.62 verifiable procedure).", 2}, {"brainpool", OPT_BRAINPOOL, "SEED", OPTION_ARG_OPTIONAL, "Generate a curve from SEED (Brainpool procedure).", 2}, {"brainpool-rfc", OPT_BRAINPOOL_RFC, "SEED", OPTION_ARG_OPTIONAL, "Generate a curve from SEED (Brainpool procedure, as per RFC 5639).", 2}, + {"nums", OPT_NUMS, 0, 0, "Generate a curve using the NUMS procedure.", 2}, {"invalid", OPT_INVALID, "RANGE", OPTION_ARG_OPTIONAL, "Generate a set of invalid curves, for a given curve (using Invalid curve algorithm).", 2}, {"twist", OPT_TWIST, 0, 0, "Generate a twist of a given curve.", 2}, @@ -175,11 +177,16 @@ static void cli_end(struct argp_state *state) { break; } - if (cfg->method == METHOD_SEED && cfg->seed_algo == SEED_BRAINPOOL && + if (cfg->method == METHOD_SEED && (cfg->seed_algo == SEED_BRAINPOOL || cfg->seed_algo == SEED_BRAINPOOL_RFC) && cfg->field == FIELD_BINARY) { argp_failure(state, 1, 0, "Brainpool algorithm only creates prime field curves."); } + if (cfg->method == METHOD_SEED && cfg->seed_algo == SEED_NUMS && + cfg->field == FIELD_BINARY) { + argp_failure(state, 1, 0, + "NUMS algorithm only creates prime field curves."); + } if (cfg->method == METHOD_CM && cfg->field == FIELD_BINARY) { argp_failure(state, 1, 0, "Complex multiplication only creates prime field curves."); @@ -266,6 +273,10 @@ error_t cli_parse(int key, char *arg, struct argp_state *state) { cfg->seed = arg; } break; + case OPT_NUMS: + cfg->method |= METHOD_SEED; + cfg->seed_algo = SEED_NUMS; + break; case OPT_BRAINPOOL_RFC: cfg->method |= METHOD_SEED; cfg->seed_algo = SEED_BRAINPOOL_RFC; diff --git a/src/io/output.c b/src/io/output.c index 12b412d..a69b905 100644 --- a/src/io/output.c +++ b/src/io/output.c @@ -181,40 +181,40 @@ char *output_sjson_begin() { return output_malloc("[\n"); } char *output_sjson_end() { return output_malloc("]\n"); } -void output_f(FILE *out, curve_t *curve) { +void output_f(FILE *output, curve_t *curve) { char *s = output_s(curve); if (s) { - fprintf(out, "%s", s); + fprintf(output, "%s", s); try_free(s); } } void output_o(curve_t *curve) { output_f(out, curve); } -void output_f_separator(FILE *out) { +void output_f_separator(FILE *output) { char *s = output_s_separator(); if (s) { - fprintf(out, "%s", s); + fprintf(output, "%s", s); try_free(s); } } void output_o_separator() { output_f_separator(out); } -void output_f_begin(FILE *out) { +void output_f_begin(FILE *output) { char *s = output_s_begin(); if (s) { - fprintf(out, "%s", s); + fprintf(output, "%s", s); try_free(s); } } void output_o_begin() { output_f_begin(out); } -void output_f_end(FILE *out) { +void output_f_end(FILE *output) { char *s = output_s_end(); if (s) { - fprintf(out, "%s", s); + fprintf(output, "%s", s); try_free(s); } } diff --git a/src/misc/config.h b/src/misc/config.h index d73d26f..dcdca58 100644 --- a/src/misc/config.h +++ b/src/misc/config.h @@ -59,7 +59,8 @@ typedef enum { SEED_ANSI, SEED_BRAINPOOL, SEED_BRAINPOOL_RFC, - SEED_FIPS + SEED_FIPS, + SEED_NUMS } seed_e; /**