+ kd = key_newstruct();
+ key_structsteal(kd, "n", key_newmp(KCAT_PUB, bp.n));
+
+ kkd = key_newstruct();
+ key_structsteal(kkd, "p", key_newmp(KCAT_PRIV | KF_BURN, bp.p));
+ key_structsteal(kkd, "q", key_newmp(KCAT_PRIV | KF_BURN, bp.q));
+ dolock(k, &kkd, "private");
+ key_structsteal(kd, "private", kkd);
+ key_setkeydata(k->kf, k->k, kd);
+ key_drop(kd);
+
+ bbs_privfree(&bp);
+}
+
+static void alg_binparam(keyopts *k)
+{
+ static const char *pl[] = { "p", "q", "g", 0 };
+ if (!copyparam(k, pl)) {
+ gbin_param gb;
+ qd_parse qd;
+ group *g;
+ const char *e;
+ key_data *kd;
+
+ /* --- Decide on a field --- */
+
+ if (!k->bits) k->bits = 128;
+ if (k->curve && strcmp(k->curve, "list") == 0) {
+ unsigned i, w;
+ LIST("Built-in binary fields", stdout,
+ bintab[i].name, bintab[i].name);
+ exit(0);
+ }
+ if (!k->curve) {
+ if (k->bits <= 40) k->curve = "p1363-40";
+ else if (k->bits <= 56) k->curve = "p1363-56";
+ else if (k->bits <= 64) k->curve = "p1363-64";
+ else if (k->bits <= 80) k->curve = "p1363-80";
+ else if (k->bits <= 112) k->curve = "p1363-112";
+ else if (k->bits <= 128) k->curve = "p1363-128";
+ else {
+ die(EXIT_FAILURE,
+ "no built-in binary fields provide %u-bit security",
+ k->bits);
+ }
+ }
+
+ /* --- Check it --- */
+
+ qd.e = 0;
+ qd.p = k->curve;
+ if (dhbin_parse(&qd, &gb))
+ die(EXIT_FAILURE, "error in field spec: %s", qd.e);
+ if (!qd_eofp(&qd))
+ die(EXIT_FAILURE, "junk at end of field spec");
+ if ((g = group_binary(&gb)) == 0)
+ die(EXIT_FAILURE, "invalid binary field");
+ if (!(k->f & f_quiet) && (e = G_CHECK(g, &rand_global)) != 0)
+ moan("WARNING! group check failed: %s", e);
+ G_DESTROYGROUP(g);
+
+ /* --- Write out the answer --- */
+
+ kd = key_newstruct();
+ key_structsteal(kd, "p", key_newmp(KCAT_SHARE, gb.p));
+ key_structsteal(kd, "q", key_newmp(KCAT_SHARE, gb.q));
+ key_structsteal(kd, "g", key_newmp(KCAT_SHARE, gb.g));
+ mp_drop(gb.q);
+ mp_drop(gb.p);
+ mp_drop(gb.g);
+ key_setkeydata(k->kf, k->k, kd);
+ key_drop(kd);
+ }
+}
+
+static void alg_bin(keyopts *k)
+{
+ mp *x, *y;
+ mp *p, *q, *g;
+ gfreduce r;
+ key_data *kd, *kkd;
+
+ /* --- Get the shared parameters --- */
+
+ alg_binparam(k);
+ key_split(&k->k->k); kd = k->k->k;
+ p = getmp(kd, "p");
+ q = getmp(kd, "q");
+ g = getmp(kd, "g");
+
+ /* --- Choose a suitable private key --- *
+ *
+ * Since %$g$% has order %$q$%, choose %$x < q$%.
+ */
+
+ x = mprand_range(MP_NEWSEC, q, k->r, 0);
+
+ /* --- Compute the public key %$y = g^x \bmod p$% --- */
+
+ gfreduce_create(&r, p);
+ y = gfreduce_exp(&r, MP_NEW, g, x);
+ gfreduce_destroy(&r);
+
+ /* --- Store everything away --- */
+
+ key_structsteal(kd, "y", key_newmp(KCAT_PUB, y));
+
+ kkd = key_newstruct();
+ key_structsteal(kkd, "x", key_newmp(KCAT_PRIV | KF_BURN, x));
+ dolock(k, &kkd, "private");
+ key_structsteal(kd, "private", kkd);
+
+ mp_drop(x); mp_drop(y);
+}
+
+static void alg_ecparam(keyopts *k)
+{
+ static const char *pl[] = { "curve", 0 };
+ if (!copyparam(k, pl)) {
+ ec_info ei;
+ const char *e;
+ key_data *kd;
+
+ /* --- Decide on a curve --- */
+
+ if (!k->bits) k->bits = 256;
+ if (k->curve && strcmp(k->curve, "list") == 0) {
+ unsigned i, w;
+ LIST("Built-in elliptic curves", stdout,
+ ectab[i].name, ectab[i].name);
+ exit(0);
+ }
+ if (!k->curve) {
+ if (k->bits <= 56) k->curve = "secp112r1";
+ else if (k->bits <= 64) k->curve = "secp128r1";
+ else if (k->bits <= 80) k->curve = "secp160r1";
+ else if (k->bits <= 96) k->curve = "secp192r1";
+ else if (k->bits <= 112) k->curve = "secp224r1";
+ else if (k->bits <= 128) k->curve = "secp256r1";
+ else if (k->bits <= 192) k->curve = "secp384r1";
+ else if (k->bits <= 256) k->curve = "secp521r1";
+ else
+ die(EXIT_FAILURE, "no built-in curves provide %u-bit security",
+ k->bits);
+ }
+
+ /* --- Check it --- */
+
+ if ((e = ec_getinfo(&ei, k->curve)) != 0)
+ die(EXIT_FAILURE, "error in curve spec: %s", e);
+ if (!(k->f & f_quiet) && (e = ec_checkinfo(&ei, k->r)) != 0)
+ moan("WARNING! curve check failed: %s", e);
+ ec_freeinfo(&ei);
+
+ /* --- Write out the answer --- */
+
+ kd = key_newstruct();
+ key_structsteal(kd, "curve", key_newstring(KCAT_SHARE, k->curve));
+ key_setkeydata(k->kf, k->k, kd);
+ key_drop(kd);
+ }
+}
+
+static void alg_ec(keyopts *k)
+{
+ key_data *kd;
+ key_data *kkd;
+ mp *x = MP_NEW;
+ ec p = EC_INIT;
+ const char *e;
+ ec_info ei;
+
+ /* --- Get the curve --- */
+
+ alg_ecparam(k);
+ key_split(&k->k->k); kd = k->k->k;
+ if ((kkd = key_structfind(kd, "curve")) == 0)
+ die(EXIT_FAILURE, "unexpected failure looking up subkey `curve')");
+ if ((kkd->e & KF_ENCMASK) != KENC_STRING)
+ die(EXIT_FAILURE, "subkey `curve' is not a string");
+ if ((e = ec_getinfo(&ei, kkd->u.p)) != 0)
+ die(EXIT_FAILURE, "error in curve spec: %s", e);
+
+ /* --- Invent a private exponent and compute the public key --- */
+
+ x = mprand_range(MP_NEWSEC, ei.r, k->r, 0);
+ ec_mul(ei.c, &p, &ei.g, x);
+
+ /* --- Store everything away --- */
+
+ key_structsteal(kd, "p", key_newec(KCAT_PUB, &p));
+
+ kkd = key_newstruct();
+ key_structsteal(kkd, "x", key_newmp(KCAT_PRIV | KF_BURN, x));
+ dolock(k, &kkd, "private");
+ key_structsteal(kd, "private", kkd);