Slight reorganization. Add elliptic curves from X9.62.
[u/mdw/catacomb] / utils / ecptdecompress.c
diff --git a/utils/ecptdecompress.c b/utils/ecptdecompress.c
new file mode 100644 (file)
index 0000000..dcfdcbd
--- /dev/null
@@ -0,0 +1,137 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <mLib/alloc.h>
+#include <mLib/hex.h>
+#include <mLib/dstr.h>
+
+#include "ec.h"
+#include "mp.h"
+#include "rand.h"
+
+static void puthex(const char *name, mp *x, size_t n)
+{
+  dstr d = DSTR_INIT;
+  hex_ctx hc;
+  char *p;
+
+  if (!n) n = mp_octets(x);
+  p = xmalloc(n);
+  hex_init(&hc);
+  hc.indent = "";
+  hc.maxline = 0;
+  mp_storeb(x, p, n);
+  hex_encode(&hc, p, n, &d);
+  hex_encode(&hc, 0, 0, &d);
+  printf("  %s 0x", name);
+  dstr_write(&d, stdout);
+  putchar('\n');
+  dstr_destroy(&d);
+  xfree(p);
+}
+
+int main(int argc, char *argv[])
+{
+  ec_curve *c;
+  ec_info ei;
+  ec pt = EC_INIT;
+  qd_parse qd;
+  hex_ctx hc;
+  dstr d = DSTR_INIT;
+  size_t n;
+  octet *p;
+  mp *x, *y = 0, *yy = 0;
+  const char *err;
+
+  qd.p = argv[1];
+  qd.e = 0;
+  if ((c = ec_curveparse(&qd)) == 0 || !qd_eofp(&qd)) {
+    fprintf(stderr, "bad curve: %s\n", qd.e);
+    exit(1);
+  }
+  n = c->f->noctets;
+
+  ei.c = c;
+  ei.r = mp_readstring(MP_NEW, argv[2], 0, 0);
+  ei.h = mp_readstring(MP_NEW, argv[3], 0, 0);
+
+  EC_CREATE(&ei.g);
+  hex_init(&hc);
+  hex_decode(&hc, argv[4], strlen(argv[4]), &d);
+  hex_decode(&hc, 0, 0, &d);
+  p = (octet *)d.buf;
+  if (p[0] == 0) {
+    EC_SETINF(&ei.g);
+  } else {
+    if (d.len < n + 1) {
+      fprintf(stderr, "missing x\n");
+      exit(1);
+    }
+    x = mp_loadb(MP_NEW, p + 1, n);
+    if (p[0] & 0x04) {
+      if (d.len < 2 * n + 1) {
+       fprintf(stderr, "missing y\n");
+       exit(1);
+      }
+      y = mp_loadb(MP_NEW, p + n + 1, n);
+    }
+    if (p[0] & 0x02) {
+      if (!EC_FIND(c, &pt, x)) {
+       fprintf(stderr, "no matching y\n");
+       exit(1);
+      }
+      yy = MP_COPY(pt.y);
+      ec_destroy(&pt);
+      switch (F_TYPE(c->f)) {
+       case FTY_PRIME:
+         if (!MP_ISODD(yy) != !(p[0] & 1))
+           yy = mp_sub(yy, c->f->m, yy);
+         break;
+       case FTY_BINARY:
+         if (MP_ISZERO(x))
+           yy = F_SQRT(c->f, MP_NEW, c->b);
+         else {
+           mp *xx = F_SQR(c->f, MP_NEW, x);
+           mp *b = F_MUL(c->f, MP_NEW, xx, c->a);
+           mp *xxx = F_MUL(c->f, MP_NEW, xx, x);
+           b = F_ADD(c->f, b, b, xxx);
+           b = F_ADD(c->f, b, b, c->b);
+           xx = F_INV(c->f, xx, xx);
+           b = F_MUL(c->f, b, b, xx);
+           mp_drop(xxx);
+           mp_drop(xx);
+           yy = F_QUADSOLVE(c->f, MP_NEW, b);
+           if (!MP_ISODD(yy) != !(p[0] & 1))
+             yy = mp_add(yy, yy, MP_ONE);
+           yy = F_MUL(c->f, yy, yy, x);
+         }
+         break;
+       default:
+         abort();
+      }
+    }
+    if (y && yy && !MP_EQ(y, yy)) {
+      fprintf(stderr, "inconsistent answers\n");
+      exit(1);
+    }
+    ei.g.x = x;
+    ei.g.y = mp_copy(y ? y : yy);
+    mp_drop(y); mp_drop(yy);
+  }
+
+  if ((err = ec_checkinfo(&ei, &rand_global)) != 0) {
+    fprintf(stderr, "bad curve: %s\n", err);
+    exit(0);
+  }
+  puthex("p", ei.c->f->m, 0);
+  puthex("a", ei.c->a, c->f->noctets);
+  puthex("b", ei.c->b, c->f->noctets);
+  puthex("r", ei.r, c->f->noctets);
+  printf("  h "); mp_writefile(ei.h, stdout, 10); putchar('\n');
+  puthex("gx", ei.g.x, c->f->noctets);
+  puthex("gy", ei.g.y, c->f->noctets);
+  ec_freeinfo(&ei);
+  dstr_destroy(&d);
+  return (0);
+}