progs/perftest.c: Use from Glibc syscall numbers.
[catacomb] / math / ec-raw.c
index 54310c8..497e191 100644 (file)
 
 /*----- Main code ---------------------------------------------------------*/
 
-/* --- @ec_putraw@ --- *
+/* --- @ec_ec2osp@ --- *
  *
  * Arguments:  @ec_curve *c@ = elliptic curve
+ *             @unsigned f@ = format flags for output
  *             @buf *b@ = pointer to a buffer
  *             @const ec *p@ = an elliptic curve point
  *
  * Returns:    Zero on success, nonzero on failure.
  *
  * Use:                Puts an elliptic curve point to the given buffer using the
- *             standard uncompressed format described in P1383 and SEC1.
+ *             standard uncompressed format described in P1363 and SEC1.
  *             This requires at most @1 + 2 * c->f->noctets@ space in the
- *             buffer.  We don't do point compression.
+ *             buffer.
+ *
+ *             Point compression features are determined by @f@ as follows.
+ *             If @EC_CMPR@ is set then point compression is performed and a
+ *             compressed form of the %$y$%-coordinate is contained in the
+ *             first output byte; if @EC_SORT@ is set then P1363a `SORT'
+ *             compression is used, otherwise LSB compression.  If
+ *             @EC_EXPLY@ is set, then an explicit %$y$%-coordinate is
+ *             output in full.  Otherwise the %$y$%-coordinate is
+ *             suppressed.
+ *
+ *             Returns failure (@-1@) if the flags are invalid, or if there
+ *             isn't enough space in the output buffer.
  */
 
-int ec_putraw(ec_curve *c, buf *b, const ec *p)
+int ec_ec2osp(ec_curve *c, unsigned f, buf *b, const ec *p)
 {
   octet *q;
   size_t n;
+  ec t = EC_INIT;
+
+  /* --- Check the requested flags for sanity --- */
+
+  if (!f) f = EC_XONLY;
+  if (f & ~((f & EC_XONLY) ? EC_XONLY :
+           (f & EC_CMPR) ? (EC_CMPR | EC_EXPLY | EC_SORT) :
+           (f & EC_EXPLY) ? EC_EXPLY :
+           0u))
+    return (-1);
+
+  /* --- Point at infinity --- */
 
   if (EC_ATINF(p)) return (buf_putbyte(b, 0));
-  buf_putbyte(b, 4);
+
+  /* --- Fix up the format byte, compressing the %$y$%-coordinate --- */
+
+  if (f & EC_CMPR) {
+    if (!(f & EC_SORT))
+      f |= EC_COMPR(c, p) ? EC_YBIT : 0;
+    else {
+      ec_neg(c, &t, p);
+      f |= MP_CMP(p->y, >, t.y);
+      EC_DESTROY(&t);
+    }
+  }
+
+  /* --- Write the format byte --- */
+
+  if (buf_putbyte(b, f)) return (-1);
+
+  /* --- Write the %$x$%-coordinate --- */
+
   n = c->f->noctets;
-  if ((q = buf_get(b, n * 2)) == 0) return (-1);
+  if ((q = buf_get(b, n)) == 0) return (-1);
   mp_storeb(p->x, q, n);
-  mp_storeb(p->y, q + n, n);
+
+  /* --- Write the %$y$%-coordinate if we need one --- */
+
+  if (f & EC_EXPLY) {
+    if ((q = buf_get(b, n)) == 0) return (-1);
+    mp_storeb(p->y, q, n);
+  }
+
+  /* --- All done --- */
+
   return (0);
 }
 
-/* --- @ec_getraw@ --- *
+/* --- @ec_os2ecp@ --- *
  *
- * Arguments:  @ec_curve *c@ = elliptic curve
+ * Arguments:  @ec_curve *c = elliptic curve
+ *             @unsigned f@ = format flags for input
  *             @buf *b@ = pointer to a buffer
  *             @ec *d@ = an elliptic curve point
  *
  * Returns:    Zero on success, nonzero on failure.
  *
  * Use:                Reads an elliptic curve point from the given buffer using the
- *             standard uncompressed format described in P1383 and SEC1.
- *             We don't do point compression.
+ *             standard uncompressed format described in P1363 and SEC1.
+ *
+ *             Point compression features are determined by @f@ as follows.
+ *             If @EC_LSB@ is set, then accept an LSB-compressed %$y$%-
+ *             coordinate; if @EC_SORT@ is set, then accept a SORT-
+ *             compressed %$y$%-coordinate; if @EC_EXPLY@ is set, then
+ *             accept an explicit %$y$%-coordinate; if @EC_XONLY@ is set
+ *             then accept a bare %$x$%-coordinate (a correct
+ *             %$y$%-coordinate is chosen arbitrarily).  Hybrid forms are
+ *             acceptable, and the input is checked to verify that the
+ *             redundant representations are consistent.  If no flags are
+ *             set in @f@, then no input (other than the point at infinity)
+ *             will be acceptable.
  */
 
-int ec_getraw(ec_curve *c, buf *b, ec *d)
+int ec_os2ecp(ec_curve *c, unsigned f, buf *b, ec *d)
 {
   const octet *q;
   size_t n;
-  int u;
+  ec t = EC_INIT, tt = EC_INIT;
+  mp *x = MP_NEW, *y = MP_NEW;
+  int g, gwant;
+  int rc = -1;
+
+  /* --- Read the format byte --- */
+
+  if ((g = buf_getbyte(b)) < 0) goto done;
+
+  /* --- Point at infinity --- */
+
+  if (!g) { EC_SETINF(d); rc = 0; goto done; }
+
+  /* --- Fetch the %$x$%-coordinate --- */
 
-  if ((u = buf_getbyte(b)) < 0) return (-1);
-  if (!u) { EC_SETINF(d); return (0); }
-  if (!(u & 4)) return (-1);
   n = c->f->noctets;
-  if ((q = buf_get(b, n * 2)) == 0) return (-1);
-  EC_DESTROY(d);
-  d->x = mp_loadb(MP_NEW, q, n);
-  d->y = mp_loadb(MP_NEW, q + n, n);
-  d->z = 0;
-  return (0);
+  if ((q = buf_get(b, n)) == 0) goto done;
+  x = mp_loadb(x, q, n);
+
+  /* --- If we're compressing then figure out the right value --- *
+   *
+   * Also check that the format is acceptable to the caller.
+   */
+
+  switch (g & ~EC_EXPLY) {
+    case 0:
+      t.x = x; x = MP_NEW; break;
+    case EC_XONLY:
+      gwant = EC_XONLY; goto decompr;
+    case EC_CMPR: case EC_CMPR | EC_YBIT:
+      gwant = EC_LSB; goto decompr;
+    case EC_CMPR | EC_SORT: case EC_CMPR | EC_SORT | EC_YBIT:
+      gwant = EC_SORT; goto decompr;
+    default: goto done;
+    decompr:
+      if (!(f & gwant)) goto done;
+      if (!ec_find(c, &t, x)) goto done;
+      switch (gwant) {
+       case EC_LSB:
+         if (!EC_COMPR(c, &t) != !(g & EC_YBIT)) ec_neg(c, &t, &t);
+         if (!EC_COMPR(c, &t) != !(g & EC_YBIT)) goto done;
+         break;
+       case EC_SORT:
+         ec_neg(c, &tt, &t);
+         if (!MP_CMP(t.y, >, tt.y) != !(g & EC_YBIT)) {
+           if (MP_EQ(t.y, tt.y)) goto done;
+           MP_DROP(t.y); t.y = MP_COPY(tt.y);
+         }
+         break;
+       case EC_XONLY:
+         break;
+       default:
+         abort();
+      }
+  }
+
+  /* --- If an explicit %$y$%-coordinate is specified, read it in --- */
+
+  if (g & EC_EXPLY) {
+    if (!(f & EC_EXPLY)) goto done;
+    if ((q = buf_get(b, n)) == 0) goto done;
+    y = mp_loadb(y, q, n);
+    if (!t.y) t.y = MP_COPY(y);
+    else if (!MP_EQ(y, t.y)) goto done;
+  }
+
+  /* --- We're ready --- */
+
+  EC_COPY(d, &t);
+  rc = 0;
+
+  /* --- Clean up --- */
+
+done:
+  if (x) MP_DROP(x);
+  if (y) MP_DROP(y);
+  if (t.x) MP_DROP(t.x); if (t.y) MP_DROP(t.y);
+  EC_DESTROY(&tt);
+  return (rc);
 }
 
+/* --- @ec_putraw@ --- *
+ *
+ * Arguments:  @ec_curve *c@ = elliptic curve
+ *             @buf *b@ = pointer to a buffer
+ *             @const ec *p@ = an elliptic curve point
+ *
+ * Returns:    Zero on success, nonzero on failure.
+ *
+ * Use:                Puts an elliptic curve point to the given buffer using the
+ *             standard uncompressed format described in P1363 and SEC1.
+ *             This requires at most @1 + 2 * c->f->noctets@ space in the
+ *             buffer.  We don't do point compression.
+ */
+
+int ec_putraw(ec_curve *c, buf *b, const ec *p)
+  { return (ec_ec2osp(c, EC_EXPLY, b, p)); }
+
+/* --- @ec_getraw@ --- *
+ *
+ * Arguments:  @ec_curve *c@ = elliptic curve
+ *             @buf *b@ = pointer to a buffer
+ *             @ec *d@ = an elliptic curve point
+ *
+ * Returns:    Zero on success, nonzero on failure.
+ *
+ * Use:                Reads an elliptic curve point from the given buffer using the
+ *             standard uncompressed format described in P1363 and SEC1.
+ *             We don't do point compression.
+ */
+
+int ec_getraw(ec_curve *c, buf *b, ec *d)
+  { return (ec_os2ecp(c, EC_LSB | EC_SORT | EC_EXPLY, b, d)); }
+
 /*----- That's all, folks -------------------------------------------------*/