progs/: Generate XDH and EdDSA operations using macros.
authorMark Wooding <mdw@distorted.org.uk>
Thu, 11 May 2017 09:42:15 +0000 (10:42 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 14 May 2017 13:58:41 +0000 (14:58 +0100)
There are already two very similar XDH implementations, and EdDSA is
likely to have more.  Let's not write more code than we need to.

progs/cc-kem.c
progs/cc-sig.c
progs/key.c

index 5b0cbf7..cf53eaf 100644 (file)
@@ -604,135 +604,79 @@ static const kemops ec_decops = {
   ec_decinit, dh_decdoit, dh_enccheck, dh_encdestroy
 };
 
-/* --- X25519 --- */
-
-static kem *x25519_encinit(key *k, void *kd) { return (CREATE(kem)); }
-static void x25519_encdestroy(kem *k) { DESTROY(k); }
-
-static const char *x25519_enccheck(kem *k)
-{
-  x25519_pub *kd = k->kd;
-
-  if (kd->pub.sz != X25519_PUBSZ)
-    return ("incorrect X25519 public key length");
-  return (0);
-}
-
-static int x25519_encdoit(kem *k, dstr *d, ghash *h)
-{
-  octet t[X25519_KEYSZ], z[X25519_OUTSZ];
-  x25519_pub *kd = k->kd;
-
-  rand_get(RAND_GLOBAL, t, sizeof(t));
-  dstr_ensure(d, X25519_PUBSZ);
-  x25519((octet *)d->buf, t, x25519_base);
-  x25519(z, t, kd->pub.k);
-  d->len += X25519_PUBSZ;
-  GH_HASH(h, d->buf, X25519_PUBSZ);
-  GH_HASH(h, z, X25519_OUTSZ);
-  return (0);
-}
-
-static const char *x25519_deccheck(kem *k)
-{
-  x25519_priv *kd = k->kd;
-
-  if (kd->priv.sz != X25519_KEYSZ)
-    return ("incorrect X25519 private key length");
-  if (kd->pub.sz != X25519_PUBSZ)
-    return ("incorrect X25519 public key length");
-  return (0);
-}
-
-static int x25519_decdoit(kem *k, dstr *d, ghash *h)
-{
-  octet z[X25519_OUTSZ];
-  x25519_priv *kd = k->kd;
-  int rc = -1;
-
-  if (d->len != X25519_PUBSZ) goto done;
-  x25519(z, kd->priv.k, (const octet *)d->buf);
-  GH_HASH(h, d->buf, X25519_PUBSZ);
-  GH_HASH(h, z, X25519_OUTSZ);
-  rc = 0;
-done:
-  return (rc);
-}
-
-static const kemops x25519_encops = {
-  x25519_pubfetch, sizeof(x25519_pub),
-  x25519_encinit, x25519_encdoit, x25519_enccheck, x25519_encdestroy
-};
-
-static const kemops x25519_decops = {
-  x25519_privfetch, sizeof(x25519_priv),
-  x25519_encinit, x25519_decdoit, x25519_deccheck, x25519_encdestroy
-};
-
-/* --- X448 --- */
-
-static kem *x448_encinit(key *k, void *kd) { return (CREATE(kem)); }
-static void x448_encdestroy(kem *k) { DESTROY(k); }
-
-static const char *x448_enccheck(kem *k)
-{
-  x448_pub *kd = k->kd;
-
-  if (kd->pub.sz != X448_PUBSZ)
-    return ("incorrect X448 public key length");
-  return (0);
-}
-
-static int x448_encdoit(kem *k, dstr *d, ghash *h)
-{
-  octet t[X448_KEYSZ], z[X448_OUTSZ];
-  x448_pub *kd = k->kd;
-
-  rand_get(RAND_GLOBAL, t, sizeof(t));
-  dstr_ensure(d, X448_PUBSZ);
-  x448((octet *)d->buf, t, x448_base);
-  x448(z, t, kd->pub.k);
-  d->len += X448_PUBSZ;
-  GH_HASH(h, d->buf, X448_PUBSZ);
-  GH_HASH(h, z, X448_OUTSZ);
-  return (0);
-}
-
-static const char *x448_deccheck(kem *k)
-{
-  x448_priv *kd = k->kd;
-
-  if (kd->priv.sz != X448_KEYSZ)
-    return ("incorrect X448 private key length");
-  if (kd->pub.sz != X448_PUBSZ)
-    return ("incorrect X448 public key length");
-  return (0);
-}
-
-static int x448_decdoit(kem *k, dstr *d, ghash *h)
-{
-  octet z[X448_OUTSZ];
-  x448_priv *kd = k->kd;
-  int rc = -1;
-
-  if (d->len != X448_PUBSZ) goto done;
-  x448(z, kd->priv.k, (const octet *)d->buf);
-  GH_HASH(h, d->buf, X448_PUBSZ);
-  GH_HASH(h, z, X448_OUTSZ);
-  rc = 0;
-done:
-  return (rc);
-}
-
-static const kemops x448_encops = {
-  x448_pubfetch, sizeof(x448_pub),
-  x448_encinit, x448_encdoit, x448_enccheck, x448_encdestroy
-};
-
-static const kemops x448_decops = {
-  x448_privfetch, sizeof(x448_priv),
-  x448_encinit, x448_decdoit, x448_deccheck, x448_encdestroy
-};
+/* --- X25519 and similar schemes --- */
+
+#define XDHS(_)                                                                \
+  _(x25519, X25519)                                                    \
+  _(x448, X448)
+
+#define XDHDEF(xdh, XDH)                                               \
+                                                                       \
+  static kem *xdh##_encinit(key *k, void *kd) { return (CREATE(kem)); }        \
+  static void xdh##_encdestroy(kem *k) { DESTROY(k); }                 \
+                                                                       \
+  static const char *xdh##_enccheck(kem *k)                            \
+  {                                                                    \
+    xdh##_pub *kd = k->kd;                                             \
+                                                                       \
+    if (kd->pub.sz != XDH##_PUBSZ)                                     \
+      return ("incorrect " #XDH "public key length");                  \
+    return (0);                                                                \
+  }                                                                    \
+                                                                       \
+  static int xdh##_encdoit(kem *k, dstr *d, ghash *h)                  \
+  {                                                                    \
+    octet t[XDH##_KEYSZ], z[XDH##_OUTSZ];                              \
+    xdh##_pub *kd = k->kd;                                             \
+                                                                       \
+    rand_get(RAND_GLOBAL, t, sizeof(t));                               \
+    dstr_ensure(d, XDH##_PUBSZ);                                       \
+    xdh((octet *)d->buf, t, xdh##_base);                               \
+    xdh(z, t, kd->pub.k);                                              \
+    d->len += XDH##_PUBSZ;                                             \
+    GH_HASH(h, d->buf, XDH##_PUBSZ);                                   \
+    GH_HASH(h, z, XDH##_OUTSZ);                                                \
+    return (0);                                                                \
+  }                                                                    \
+                                                                       \
+  static const char *xdh##_deccheck(kem *k)                            \
+  {                                                                    \
+    xdh##_priv *kd = k->kd;                                            \
+                                                                       \
+    if (kd->priv.sz != XDH##_KEYSZ)                                    \
+      return ("incorrect " #XDH " private key length");                        \
+    if (kd->pub.sz != XDH##_PUBSZ)                                     \
+      return ("incorrect " #XDH " public key length");                 \
+    return (0);                                                                \
+  }                                                                    \
+                                                                       \
+  static int xdh##_decdoit(kem *k, dstr *d, ghash *h)                  \
+  {                                                                    \
+    octet z[XDH##_OUTSZ];                                              \
+    xdh##_priv *kd = k->kd;                                            \
+    int rc = -1;                                                       \
+                                                                       \
+    if (d->len != XDH##_PUBSZ) goto done;                              \
+    xdh(z, kd->priv.k, (const octet *)d->buf);                         \
+    GH_HASH(h, d->buf, XDH##_PUBSZ);                                   \
+    GH_HASH(h, z, XDH##_OUTSZ);                                                \
+    rc = 0;                                                            \
+  done:                                                                        \
+    return (rc);                                                       \
+  }                                                                    \
+                                                                       \
+  static const kemops xdh##_encops = {                                 \
+    xdh##_pubfetch, sizeof(xdh##_pub),                                 \
+    xdh##_encinit, xdh##_encdoit, xdh##_enccheck, xdh##_encdestroy     \
+  };                                                                   \
+                                                                       \
+  static const kemops xdh##_decops = {                                 \
+    xdh##_privfetch, sizeof(xdh##_priv),                               \
+    xdh##_encinit, xdh##_decdoit, xdh##_deccheck, xdh##_encdestroy     \
+  };
+
+XDHS(XDHDEF)
+#undef XDHDEF
 
 /* --- Symmetric --- */
 
@@ -802,8 +746,10 @@ const struct kemtab kemtab[] = {
   { "dh",      &dh_encops,     &dh_decops },
   { "bindh",   &bindh_encops,  &bindh_decops },
   { "ec",      &ec_encops,     &ec_decops },
-  { "x25519",  &x25519_encops, &x25519_decops },
-  { "x448",    &x448_encops,   &x448_decops },
+#define XDHTAB(xdh, XDH)                                               \
+  { #xdh,      &xdh##_encops,  &xdh##_decops },
+  XDHS(XDHTAB)
+#undef XDHTAB
   { "symm",    &symm_encops,   &symm_decops },
   { 0,         0,              0 }
 };
index f14b4b8..7303c56 100644 (file)
@@ -574,60 +574,73 @@ static const sigops eckcdsa_vrf = {
   eckcdsa_vrfinit, kcdsa_vrfdoit, dsa_sigcheck, dsa_sigdestroy
 };
 
-/* --- Ed25519 --- */
+/* --- EdDSA --- */
 
-static sig *ed25519_siginit(key *k, void *kd, const gchash *hc)
-  { sig *s = CREATE(sig); s->h = 0; return (s); }
+#define EDDSAS(_)                                                      \
+  _(ed25519, ED25519, "Ed25519", sha512)
 
-static int ed25519_sigdoit(sig *s, dstr *d)
+static sig *eddsa_siginit(key *k, void *kd, const gchash *hc)
 {
-  ed25519_priv *k = s->kd;
-
-  dstr_ensure(d, ED25519_SIGSZ);
-  ed25519_sign((octet *)d->buf, k->priv.k, k->priv.sz, k->pub.k,
-              GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz);
-  d->len += ED25519_SIGSZ;
-  return (0);
-}
-
-static const char *ed25519_sigcheck(sig *s)
-{
-  ed25519_priv *k = s->kd;
-
-  if (k->pub.sz != ED25519_PUBSZ)
-    return ("incorrect Ed25519 public key length");
-  return (0);
-}
-
-static void ed25519_sigdestroy(sig *s) { DESTROY(s); }
-
-static const sigops ed25519_sig = {
-  ed25519_privfetch, sizeof(ed25519_priv),
-  ed25519_siginit, ed25519_sigdoit, ed25519_sigcheck, ed25519_sigdestroy
-};
-
-static int ed25519_vrfdoit(sig *s, dstr *d)
-{
-  ed25519_pub *k = s->kd;
-
-  if (d->len != ED25519_SIGSZ) return (-1);
-  return (ed25519_verify(k->pub.k, GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz,
-                        (const octet *)d->buf));
-}
-
-static const char *ed25519_vrfcheck(sig *s)
-{
-  ed25519_pub *k = s->kd;
-
-  if (k->pub.sz != ED25519_PUBSZ)
-    return ("incorrect Ed25519 public key length");
-  return (0);
+  sig *s = CREATE(sig);
+  s->h = 0;
+  return (s);
 }
 
-static const sigops ed25519_vrf = {
-  ed25519_pubfetch, sizeof(ed25519_pub),
-  ed25519_siginit, ed25519_vrfdoit, ed25519_vrfcheck, ed25519_sigdestroy
-};
+static void eddsa_sigdestroy(sig *s) { DESTROY(s); }
+
+#define EDDSADEF(ed, ED, name, hash)                                   \
+                                                                       \
+  static int ed##_sigdoit(sig *s, dstr *d)                             \
+  {                                                                    \
+    ed##_priv *k = s->kd;                                              \
+                                                                       \
+    dstr_ensure(d, ED##_SIGSZ);                                                \
+    ed##_sign((octet *)d->buf, k->priv.k, k->priv.sz, k->pub.k,                \
+             GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz);                \
+    d->len += ED##_SIGSZ;                                              \
+    return (0);                                                                \
+  }                                                                    \
+                                                                       \
+  static const char *ed##_sigcheck(sig *s)                             \
+  {                                                                    \
+    ed##_priv *k = s->kd;                                              \
+                                                                       \
+    if (k->pub.sz != ED##_PUBSZ)                                       \
+      return ("incorrect " #name " public key length");                        \
+    return (0);                                                                \
+  }                                                                    \
+                                                                       \
+  static const sigops ed##_sig = {                                     \
+    ed##_privfetch, sizeof(ed##_priv),                                 \
+    eddsa_siginit, ed##_sigdoit, ed##_sigcheck, eddsa_sigdestroy       \
+  };                                                                   \
+                                                                       \
+  static int ed##_vrfdoit(sig *s, dstr *d)                             \
+  {                                                                    \
+    ed##_pub *k = s->kd;                                               \
+                                                                       \
+    if (d->len != ED##_SIGSZ) return (-1);                             \
+    return (ed##_verify(k->pub.k,                                      \
+                       GH_DONE(s->h, 0), GH_CLASS(s->h)->hashsz,       \
+                       (const octet *)d->buf));                        \
+  }                                                                    \
+                                                                       \
+  static const char *ed##_vrfcheck(sig *s)                             \
+  {                                                                    \
+    ed##_pub *k = s->kd;                                               \
+                                                                       \
+    if (k->pub.sz != ED##_PUBSZ)                                       \
+      return ("incorrect " #name " public key length");                        \
+    return (0);                                                                \
+  }                                                                    \
+                                                                       \
+  static const sigops ed##_vrf = {                                     \
+    ed##_pubfetch, sizeof(ed##_pub),                                   \
+    eddsa_siginit, ed##_vrfdoit, ed##_vrfcheck, eddsa_sigdestroy       \
+  };
+
+EDDSAS(EDDSADEF)
+#undef EDDSADEF
 
 /* --- Symmetric message authentication --- */
 
@@ -727,7 +740,10 @@ const struct sigtab sigtab[] = {
   { "kcdsa",   &kcdsa_sig,     &kcdsa_vrf,     &has160 },
   { "binkcdsa",        &binkcdsa_sig,  &binkcdsa_vrf,  &has160 },
   { "eckcdsa", &eckcdsa_sig,   &eckcdsa_vrf,   &has160 },
-  { "ed25519", &ed25519_sig,   &ed25519_vrf,   &sha512 },
+#define EDDSATAB(ed, ED, name, hash)                                   \
+  { #ed,       &ed##_sig,      &ed##_vrf,      &hash },
+  EDDSAS(EDDSATAB)
+#undef EDDSATAB
   { "mac",     &mac_sig,       &mac_vrf,       &rmd160 },
   { 0,         0,              0 }
 };
index e85107a..74060cd 100644 (file)
@@ -945,59 +945,62 @@ static void alg_ec(keyopts *k)
   mp_drop(x);
 }
 
-static void alg_x25519(keyopts *k)
-{
-  key_data *kd, *kkd;
-  octet priv[X25519_KEYSZ], pub[X25519_PUBSZ];
-
-  copyparam(k, 0);
-  k->r->ops->fill(k->r, priv, sizeof(priv));
-  x25519(pub, priv, x25519_base);
-  kkd = key_newstruct();
-  key_structsteal(kkd, "priv",
-                 key_newbinary(KCAT_PRIV | KF_BURN, priv, sizeof(priv)));
-  kd = key_newstruct();
-  key_structsteal(kd, "private", kkd);
-  key_structsteal(kd, "pub", key_newbinary(KCAT_PUB, pub, sizeof(pub)));
-
-  key_setkeydata(k->kf, k->k, kd);
-}
-
-static void alg_x448(keyopts *k)
-{
-  key_data *kd, *kkd;
-  octet priv[X448_KEYSZ], pub[X448_PUBSZ];
-
-  copyparam(k, 0);
-  k->r->ops->fill(k->r, priv, sizeof(priv));
-  x448(pub, priv, x448_base);
-  kkd = key_newstruct();
-  key_structsteal(kkd, "priv",
-                 key_newbinary(KCAT_PRIV | KF_BURN, priv, sizeof(priv)));
-  kd = key_newstruct();
-  key_structsteal(kd, "private", kkd);
-  key_structsteal(kd, "pub", key_newbinary(KCAT_PUB, pub, sizeof(pub)));
-
-  key_setkeydata(k->kf, k->k, kd);
-}
-
-static void alg_ed25519(keyopts *k)
-{
-  key_data *kd, *kkd;
-  octet priv[ED25519_KEYSZ], pub[ED25519_PUBSZ];
+#define XDHS(_)                                                                \
+  _(x25519, X25519, "X25519")                                          \
+  _(x448, X448, "X448")
+
+#define XDHALG(xdh, XDH, name)                                         \
+                                                                       \
+  static void alg_##xdh(keyopts *k)                                    \
+  {                                                                    \
+    key_data *kd, *kkd;                                                        \
+    octet priv[XDH##_KEYSZ], pub[XDH##_PUBSZ];                         \
+                                                                       \
+    copyparam(k, 0);                                                   \
+    k->r->ops->fill(k->r, priv, sizeof(priv));                         \
+    xdh(pub, priv, xdh##_base);                                                \
+    kkd = key_newstruct();                                             \
+    key_structsteal(kkd, "priv",                                       \
+                   key_newbinary(KCAT_PRIV | KF_BURN,                  \
+                                 priv, sizeof(priv)));                 \
+    kd = key_newstruct();                                              \
+    key_structsteal(kd, "private", kkd);                               \
+    key_structsteal(kd, "pub",                                         \
+                   key_newbinary(KCAT_PUB, pub, sizeof(pub)));         \
+                                                                       \
+    key_setkeydata(k->kf, k->k, kd);                                   \
+  }
 
-  copyparam(k, 0);
-  k->r->ops->fill(k->r, priv, sizeof(priv));
-  ed25519_pubkey(pub, priv, sizeof(priv));
-  kkd = key_newstruct();
-  key_structsteal(kkd, "priv",
-                 key_newbinary(KCAT_PRIV | KF_BURN, priv, sizeof(priv)));
-  kd = key_newstruct();
-  key_structsteal(kd, "private", kkd);
-  key_structsteal(kd, "pub", key_newbinary(KCAT_PUB, pub, sizeof(pub)));
+XDHS(XDHALG)
+#undef XDHALG
+
+#define EDDSAS(_)                                                      \
+  _(ed25519, ED25519, "Ed25519")
+
+#define EDDSAALG(ed, ED, name)                                         \
+                                                                       \
+  static void alg_##ed(keyopts *k)                                     \
+  {                                                                    \
+    key_data *kd, *kkd;                                                        \
+    octet priv[ED##_KEYSZ], pub[ED##_PUBSZ];                           \
+                                                                       \
+    copyparam(k, 0);                                                   \
+    k->r->ops->fill(k->r, priv, sizeof(priv));                         \
+    ed##_pubkey(pub, priv, sizeof(priv));                              \
+    kkd = key_newstruct();                                             \
+    key_structsteal(kkd, "priv",                                       \
+                   key_newbinary(KCAT_PRIV | KF_BURN,                  \
+                                 priv, sizeof(priv)));                 \
+    kd = key_newstruct();                                              \
+    key_structsteal(kd, "private", kkd);                               \
+    key_structsteal(kd, "pub",                                         \
+                   key_newbinary(KCAT_PUB, pub, sizeof(pub)));         \
+                                                                       \
+    key_setkeydata(k->kf, k->k, kd);                                   \
+  }
 
-  key_setkeydata(k->kf, k->k, kd);
-}
+EDDSAS(EDDSAALG)
+#undef EDDSAALG
 
 /* --- The algorithm tables --- */
 
@@ -1020,9 +1023,14 @@ static keyalg algtab[] = {
   { "bindh-param",     alg_binparam,   "Binary-field DH parameters" },
   { "ec-param",                alg_ecparam,    "Elliptic curve parameters" },
   { "ec",              alg_ec,         "Elliptic curve crypto" },
-  { "x25519",          alg_x25519,     "X25519 key exchange" },
-  { "x448",            alg_x448,       "X448 key exchange" },
-  { "ed25519",         alg_ed25519,    "Ed25519 digital signatures" },
+#define XDHTAB(xdh, XDH, name)                                         \
+  { #xdh,              alg_##xdh,      "" name " key exchange" },
+  XDHS(XDHTAB)
+#undef XDHTAB
+#define EDDSATAB(ed, ED, name)                                         \
+  { #ed,               alg_##ed,       "" name " digital signatures" },
+  EDDSAS(EDDSATAB)
+#undef EDDSATAB
   { "empty",           alg_empty,      "Empty parametrs-only key" },
   { 0,                 0 }
 };