Rearrange the file tree.
[catacomb] / pub / dsa-sign.c
diff --git a/pub/dsa-sign.c b/pub/dsa-sign.c
new file mode 100644 (file)
index 0000000..23bbf7f
--- /dev/null
@@ -0,0 +1,198 @@
+/* -*-c-*-
+ *
+ * DSA signing operation
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "dsa.h"
+#include "mp.h"
+#include "mpbarrett.h"
+#include "mpmont.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @dsa_mksig@ --- *
+ *
+ * Arguments:  @const dsa_param *dp@ = pointer to DSA parameters
+ *             @mp *a@ = secret signing key
+ *             @mp *m@ = message to be signed
+ *             @mp *k@ = random data
+ *             @mp **rr, **ss@ = where to put output parameters
+ *
+ * Returns:    ---
+ *
+ * Use:                Computes a DSA signature of a message.
+ */
+
+void dsa_mksig(const dsa_param *dp, mp *a, mp *m, mp *k, mp **rr, mp **ss)
+{
+  mpmont pm;
+  mpbarrett qb;
+  mp *k1, *r;
+  mp *ar;
+
+  /* --- Compute %$r = (g^k \bmod p) \bmod q$% --- */
+
+  mpmont_create(&pm, dp->p);
+  r = mpmont_exp(&pm, MP_NEW, dp->g, k);
+  mpmont_destroy(&pm);
+  mp_div(0, &r, r, dp->q);
+
+  /* --- Compute %$k^{-1} \bmod q$% --- */
+
+  k1 = mp_modinv(MP_NEW, k, dp->q);
+
+  /* --- Now for %$k^{-1}(m + ar)$% --- */
+
+  mpbarrett_create(&qb, dp->q);
+  ar = mp_mul(MP_NEW, a, r);
+  ar = mp_add(ar, ar, m);
+  ar = mpbarrett_reduce(&qb, ar, ar);
+  ar = mp_mul(ar, ar, k1);
+  ar = mpbarrett_reduce(&qb, ar, ar);
+  mpbarrett_destroy(&qb);
+  MP_DROP(k1);
+  if (*rr) MP_DROP(*rr);
+  if (*ss) MP_DROP(*ss);
+  *rr = r;
+  *ss = ar;
+}
+
+/* --- @dsa_sign@ --- *
+ *
+ * Arguments:  @dsa_param *dp@ = pointer to DSA parameters
+ *             @mp *a@ = pointer to secret signing key
+ *             @const void *m@ = pointer to message
+ *             @size_t msz@ = size of the message
+ *             @const void *k@ = secret random data for securing signature
+ *             @size_t ksz@ = size of secret data
+ *             @void *r@ = pointer to output space for @r@
+ *             @size_t rsz@ = size of output space for @r@
+ *             @void *s@ = pointer to output space for @s@
+ *             @size_t ssz@ = size of output space for @s@
+ *
+ * Returns:    ---
+ *
+ * Use:                Signs a message, storing the results in a big-endian binary
+ *             form.
+ */
+
+void dsa_sign(dsa_param *dp, mp *a,
+             const void *m, size_t msz, const void *k, size_t ksz,
+             void *r, size_t rsz, void *s, size_t ssz)
+{
+  mp *mm = dsa_h2n(MP_NEW, dp->q, m, msz);
+  mp *km = mp_loadb(MP_NEW, k, ksz);
+  mp *rm = MP_NEW, *sm = MP_NEW;
+  dsa_mksig(dp, a, mm, km, &rm, &sm);
+  mp_storeb(rm, r, rsz);
+  mp_storeb(sm, s, ssz);
+  mp_drop(mm); mp_drop(km);
+  mp_drop(rm); mp_drop(sm);
+}
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <mLib/testrig.h>
+
+#include "sha.h"
+
+static int verify(dstr *v)
+{
+  dsa_param dp;
+  mp *x;
+  sha_ctx c;
+  octet hash[SHA_HASHSZ];
+  dsa_sig s;
+  int ok = 1;
+
+  dp.q = *(mp **)v[0].buf;
+  dp.p = *(mp **)v[1].buf;
+  dp.g = *(mp **)v[2].buf;
+  x = *(mp **)v[3].buf;
+
+  sha_init(&c);
+  sha_hash(&c, v[4].buf, v[4].len);
+  sha_done(&c, hash);
+
+  dsa_sign(&dp, x, hash, sizeof(hash), v[5].buf, v[5].len,
+          s.r, sizeof(s.r), s.s, sizeof(s.s));
+
+  if (v[6].len != sizeof(s.r) || v[7].len != sizeof(s.s) ||
+      memcmp(s.r, v[6].buf, sizeof(s.r)) != 0 ||
+      memcmp(s.s, v[7].buf, sizeof(s.s)) != 0) {
+    fputs("\n*** signature failed", stderr);
+    fputs("\nq = ", stderr); mp_writefile(dp.q, stderr, 16);
+    fputs("\np = ", stderr); mp_writefile(dp.p, stderr, 16);
+    fputs("\ng = ", stderr); mp_writefile(dp.g, stderr, 16);
+    fputs("\nx = ", stderr); mp_writefile(x, stderr, 16);
+    fprintf(stderr, "\nmessage = `%s'", v[4].buf);
+    fputs("\nk = ", stderr); type_hex.dump(&v[5], stderr);
+    fputs("\nR = ", stderr); type_hex.dump(&v[6], stderr);
+    fputs("\nS = ", stderr); type_hex.dump(&v[7], stderr);
+
+    {
+      mp *m = MP_NEW;
+      m = mp_loadb(m, hash, sizeof(hash));
+      fputs("\nm = ", stderr); mp_writefile(m, stderr, 16);
+      m = mp_loadb(m, s.r, sizeof(s.r));
+      fputs("\nr = ", stderr); mp_writefile(m, stderr, 16);
+      m = mp_loadb(m, s.s, sizeof(s.s));
+      fputs("\ns = ", stderr); mp_writefile(m, stderr, 16);
+      mp_drop(m);
+    }
+
+    fputc('\n', stderr);
+    ok = 0;
+  }
+
+  mp_drop(dp.p);
+  mp_drop(dp.q);
+  mp_drop(dp.g);
+  mp_drop(x);
+  assert(mparena_count(MPARENA_GLOBAL) == 0);
+  return (ok);
+}
+
+static test_chunk tests[] = {
+  { "sign", verify,
+    { &type_mp, &type_mp, &type_mp, &type_mp,
+      &type_string, &type_hex, &type_hex, &type_hex, 0 } },
+  { 0, 0, { 0 } }
+};
+
+int main(int argc, char *argv[])
+{
+  sub_init();
+  test_run(argc, argv, tests, SRCDIR "/t/dsa");
+  return (0);
+}
+
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/