/*----- 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 -------------------------------------------------*/