+static const sigops ecdsa_sig = {
+ ec_privfetch, sizeof(ec_priv),
+ ecdsa_siginit, dsa_sigdoit, dsa_sigdestroy
+};
+
+static sig *dsa_vrfinit(key *k, void *kd, const gchash *hc)
+{
+ dh_pub *dp = kd;
+ dsa_sigctx *ds = dsa_doinit(k, &dp->dp, dp->y, hc);
+ return (&ds->s);
+}
+
+static sig *ecdsa_vrfinit(key *k, void *kd, const gchash *hc)
+{
+ ec_pub *ep = kd;
+ dsa_sigctx *ds = ecdsa_doinit(k, ep->cstr, &ep->p, hc);
+ return (&ds->s);
+}
+
+static int dsa_vrfdoit(sig *s, dstr *d)
+{
+ dsa_sigctx *ds = (dsa_sigctx *)s;
+ gdsa_sig ss;
+ size_t n = d->len/2;
+ int rc;
+
+ ss.r = mp_loadb(MP_NEW, d->buf, n);
+ ss.s = mp_loadb(MP_NEW, d->buf + n, d->len - n);
+ rc = gdsa_verify(&ds->g, &ss, GH_DONE(ds->s.h, 0));
+ mp_drop(ss.r); mp_drop(ss.s);
+ return (rc);
+}
+
+static const sigops dsa_vrf = {
+ dh_pubfetch, sizeof(dh_pub),
+ dsa_vrfinit, dsa_vrfdoit, dsa_sigdestroy
+};
+
+static const sigops ecdsa_vrf = {
+ ec_pubfetch, sizeof(ec_pub),
+ ecdsa_vrfinit, dsa_vrfdoit, dsa_sigdestroy
+};
+
+/* --- KCDSA and ECKCDSA --- */
+
+static void kcdsa_privkey(dsa_sigctx *ds, mp *x)
+ { ds->g.u = mp_modinv(MP_NEW, x, ds->g.g->r); }
+
+static void kcdsa_sethash(dsa_sigctx *ds, const gchash *hc)
+ { ds->s.h = gkcdsa_beginhash(&ds->g); }
+
+static sig *kcdsa_siginit(key *k, void *kd, const gchash *hc)
+{
+ dh_priv *dp = kd;
+ dsa_sigctx *ds = dsa_doinit(k, &dp->dp, dp->y, hc);
+ kcdsa_privkey(ds, dp->x);
+ kcdsa_sethash(ds, hc);
+ return (&ds->s);
+}
+
+static sig *eckcdsa_siginit(key *k, void *kd, const gchash *hc)
+{
+ ec_priv *ep = kd;
+ dsa_sigctx *ds = ecdsa_doinit(k, ep->cstr, &ep->p, hc);
+ kcdsa_privkey(ds, ep->x);
+ kcdsa_sethash(ds, hc);
+ return (&ds->s);
+}
+
+static int kcdsa_sigdoit(sig *s, dstr *d)
+{
+ dsa_sigctx *ds = (dsa_sigctx *)s;
+ gkcdsa_sig ss = GKCDSA_SIG_INIT;
+ size_t hsz = ds->g.h->hashsz, n = mp_octets(ds->g.g->r);
+
+ gkcdsa_sign(&ds->g, &ss, GH_DONE(ds->s.h, 0), 0);
+ dstr_ensure(d, hsz + n);
+ memcpy(d->buf, ss.r, hsz);
+ mp_storeb(ss.s, d->buf + hsz, n);
+ d->len += hsz + n;
+ xfree(ss.r); mp_drop(ss.s);
+ return (0);
+}
+
+static const sigops kcdsa_sig = {
+ dh_privfetch, sizeof(dh_priv),
+ kcdsa_siginit, kcdsa_sigdoit, dsa_sigdestroy
+};
+
+static const sigops eckcdsa_sig = {
+ ec_privfetch, sizeof(ec_priv),
+ eckcdsa_siginit, kcdsa_sigdoit, dsa_sigdestroy
+};
+
+static sig *kcdsa_vrfinit(key *k, void *kd, const gchash *hc)
+{
+ dh_pub *dp = kd;
+ dsa_sigctx *ds = dsa_doinit(k, &dp->dp, dp->y, hc);
+ kcdsa_sethash(ds, hc);
+ return (&ds->s);
+}
+
+static sig *eckcdsa_vrfinit(key *k, void *kd, const gchash *hc)
+{
+ ec_pub *ep = kd;
+ dsa_sigctx *ds = ecdsa_doinit(k, ep->cstr, &ep->p, hc);
+ kcdsa_sethash(ds, hc);
+ return (&ds->s);
+}
+
+static int kcdsa_vrfdoit(sig *s, dstr *d)
+{
+ dsa_sigctx *ds = (dsa_sigctx *)s;
+ gkcdsa_sig ss;
+ size_t hsz = ds->g.h->hashsz, n = d->len - hsz;
+ int rc;
+
+ if (d->len < hsz)
+ return (-1);
+ ss.r = (octet *)d->buf;
+ ss.s = mp_loadb(MP_NEW, d->buf + hsz, n);
+ rc = gkcdsa_verify(&ds->g, &ss, GH_DONE(ds->s.h, 0));
+ mp_drop(ss.s);
+ return (rc);
+}
+
+static const sigops kcdsa_vrf = {
+ dh_pubfetch, sizeof(dh_pub),
+ kcdsa_vrfinit, kcdsa_vrfdoit, dsa_sigdestroy
+};
+
+static const sigops eckcdsa_vrf = {
+ ec_pubfetch, sizeof(ec_pub),
+ eckcdsa_vrfinit, kcdsa_vrfdoit, dsa_sigdestroy
+};
+
+/* --- The switch table --- */
+
+static const struct sigtab {
+ const char *name;
+ const sigops *signops;
+ const sigops *verifyops;
+ const gchash *ch;
+} sigtab[] = {
+ { "rsapkcs1", &rsap1_sig, &rsap1_vrf, &sha },
+ { "rsapss", &rsapss_sig, &rsapss_vrf, &sha },
+ { "dsa", &dsa_sig, &dsa_vrf, &sha },
+ { "ecdsa", &ecdsa_sig, &ecdsa_vrf, &sha },
+ { "kcdsa", &kcdsa_sig, &kcdsa_vrf, &has160 },
+ { "eckcdsa", &eckcdsa_sig, &eckcdsa_vrf, &has160 },
+ { 0, 0, 0 }
+};
+
+/* --- @getsig@ --- *